Skip to content

Commit 017c2bd

Browse files
committed
Refactoring
1 parent fe557ac commit 017c2bd

File tree

10 files changed

+151
-115
lines changed

10 files changed

+151
-115
lines changed

src/hooks/useOutsideClick.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { MutableRefObject, useEffect } from 'react';
2+
3+
export default function useOutsideClick(
4+
ref: MutableRefObject<any>,
5+
fn: Function
6+
) {
7+
useEffect(() => {
8+
function handleClickOutside(event: MouseEvent) {
9+
if (ref.current && !ref.current.contains(event.target)) {
10+
fn();
11+
}
12+
}
13+
14+
document.addEventListener('mousedown', handleClickOutside);
15+
return () => {
16+
document.removeEventListener('mousedown', handleClickOutside);
17+
};
18+
}, [ref, fn]);
19+
}

src/screens/projects/ProjectsScreen.tsx

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import { Key } from 'rc-tree/lib/interface';
55
import { createUseStyles } from 'react-jss';
66
import { PlusOutlined } from '@ant-design/icons';
77

8-
import TaskInput from './components/TaskInput';
98
import rootStore from '../../modules/RootStore';
109
import TreeList from './components/TreeList';
1110
import TaskModel from '../../modules/tasks/models/TaskModel';
@@ -18,17 +17,12 @@ import DrawerTask from './components/DrawerTask/DrawerTask';
1817
import ProjectNode from './components/ProjectNode/ProjectNode';
1918
import EditProjectModal from './components/ProjectModals/EditProjectModal';
2019
import { first } from '../../helpers/ArrayHelper';
21-
import Suggestions from './components/Suggestions/Suggestions';
22-
import ObservableInput from './components/observable/ObservableInput';
20+
import CreateTask from './components/CreateTask';
2321

2422
const { Sider } = Layout;
2523

2624
const { tasksStore, projectStore } = rootStore;
2725

28-
const observableInput = new ObservableInput();
29-
30-
// const Suggestions = observer(() => <div>test</div>);
31-
3226
const TaskList = TreeList(
3327
() => tasksStore.getTasks(projectStore.activeProject),
3428
(list: TaskModel[]) => {
@@ -133,9 +127,8 @@ function ProjectsScreen() {
133127
<Layout className={style.taskList}>
134128
<div className={style.root}>
135129
<TaskList onSelect={handleSelectTask} />
136-
<div className={style.stickyTaskInput}>
137-
<Suggestions input={observableInput} />
138-
<TaskInput input={observableInput} />
130+
<div className={style.createTaskSticky}>
131+
<CreateTask />
139132
</div>
140133
</div>
141134
</Layout>
@@ -173,7 +166,7 @@ const useStyles = createUseStyles({
173166
flex: 1,
174167
height: '100%',
175168
},
176-
stickyTaskInput: {
169+
createTaskSticky: {
177170
position: 'sticky',
178171
bottom: 0,
179172
padding: '12px 0',
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import React, { FC, useMemo, useRef } from 'react';
2+
import { observer } from 'mobx-react';
3+
4+
import TaskInput from './TaskInput';
5+
import Suggestions from './Suggestions/Suggestions';
6+
import { createTaskStore } from './store/CreateTaskStore';
7+
import useOutsideClick from '../../../../hooks/useOutsideClick';
8+
9+
const handleBlur = () => createTaskStore.setFocus(false);
10+
11+
const CreateTask: FC = () => {
12+
const ref = useRef(null);
13+
14+
useOutsideClick(ref, handleBlur);
15+
16+
const showSuggestions = useMemo(() => createTaskStore.isInputEmpty, []).get();
17+
18+
return (
19+
<div ref={ref}>
20+
{showSuggestions && createTaskStore.inputFocus && <Suggestions />}
21+
<TaskInput />
22+
</div>
23+
);
24+
};
25+
26+
export default observer(CreateTask);

src/screens/projects/components/Suggestions/Suggestion.tsx renamed to src/screens/projects/components/CreateTask/Suggestions/Suggestion.tsx

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,17 @@ import React, { FC, useCallback } from 'react';
22
import { Button } from 'antd';
33
import { observer } from 'mobx-react';
44

5-
import ObservableInput from '../observable/ObservableInput';
5+
import { createTaskStore } from '../store/CreateTaskStore';
66

77
type Props = {
88
text: string;
9-
input: ObservableInput;
109
};
1110

12-
const SuggestionComp: FC<Props> = ({ text, input }: Props) => {
13-
const handleApplySuggestion = useCallback(() => input.setSuggestion(text), [
14-
input,
15-
text,
16-
]);
11+
const SuggestionComp: FC<Props> = ({ text }: Props) => {
12+
const handleApplySuggestion = useCallback(
13+
() => createTaskStore.applySuggestion(text),
14+
[text]
15+
);
1716

1817
return (
1918
<Button

src/screens/projects/components/Suggestions/Suggestions.tsx renamed to src/screens/projects/components/CreateTask/Suggestions/Suggestions.tsx

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,10 @@
11
import React, { FC, useMemo } from 'react';
22
import { observer } from 'mobx-react';
33

4+
import rootStore from '../../../../../modules/RootStore';
45
import Suggestion from './Suggestion';
5-
import ObservableInput from '../observable/ObservableInput';
6-
import rootStore from '../../../../modules/RootStore';
76

8-
type Props = {
9-
input: ObservableInput;
10-
};
11-
12-
const Suggestions: FC<Props> = ({ input }: Props) => {
7+
const Suggestions: FC = () => {
138
const suggestions = useMemo(
149
() => rootStore.tasksStore.suggestionsForProject,
1510
[]
@@ -18,11 +13,7 @@ const Suggestions: FC<Props> = ({ input }: Props) => {
1813
return (
1914
<>
2015
{suggestions.map((suggestion) => (
21-
<Suggestion
22-
key={suggestion.text}
23-
text={suggestion.text}
24-
input={input}
25-
/>
16+
<Suggestion key={suggestion.text} text={suggestion.text} />
2617
))}
2718
</>
2819
);
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import React, { ChangeEvent, KeyboardEvent, useEffect, useRef } from 'react';
2+
import { Input } from 'antd';
3+
import { observer } from 'mobx-react';
4+
import { v4 as uuid } from 'uuid';
5+
6+
import rootStore from '../../../../modules/RootStore';
7+
import TaskModel from '../../../../modules/tasks/models/TaskModel';
8+
import { createTaskStore } from './store/CreateTaskStore';
9+
10+
interface Props {
11+
className?: string;
12+
}
13+
14+
const handleCreateTask = (event: KeyboardEvent) => {
15+
// Hotkey: Enter
16+
if (event.key === 'Enter') {
17+
const { tasksStore, projectStore } = rootStore;
18+
tasksStore.add(
19+
new TaskModel({
20+
key: uuid(),
21+
title: createTaskStore.input,
22+
projectId: projectStore.activeProject,
23+
active: false,
24+
time: [],
25+
checked: false,
26+
children: [],
27+
datesInProgress: [],
28+
details: [],
29+
parent: undefined, // Add into root
30+
expanded: true,
31+
})
32+
);
33+
createTaskStore.clear();
34+
}
35+
};
36+
37+
const handleChange = (e: ChangeEvent<HTMLInputElement>) =>
38+
createTaskStore.setInput(e.target.value);
39+
40+
const handleFocus = () => createTaskStore.setFocus(true);
41+
42+
export default observer(function TaskInput({ className }: Props) {
43+
const inputRef = useRef<Input>(null);
44+
45+
useEffect(() => {
46+
inputRef.current?.focus();
47+
}, [createTaskStore.focusTrigger]);
48+
49+
return (
50+
<Input
51+
ref={inputRef}
52+
className={className}
53+
placeholder="Create task..."
54+
onKeyPress={handleCreateTask}
55+
value={createTaskStore.input}
56+
onChange={handleChange}
57+
onFocus={handleFocus}
58+
/>
59+
);
60+
});
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { default } from './CreateTask';
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { computed, makeAutoObservable } from 'mobx';
2+
3+
class CreateTaskStore {
4+
input: string = '';
5+
inputFocus: boolean = false;
6+
focusTrigger: boolean = false; // TODO better solution?
7+
8+
constructor() {
9+
makeAutoObservable(this);
10+
}
11+
12+
setInput(value: string) {
13+
return (this.input = value);
14+
}
15+
16+
applySuggestion(value: string) {
17+
this.setInput(value);
18+
this.focusTrigger = !this.focusTrigger;
19+
}
20+
21+
clear() {
22+
return (this.input = '');
23+
}
24+
25+
isInputEmpty = computed(() => this.input.length === 0);
26+
27+
setFocus(isFocus: boolean) {
28+
this.inputFocus = isFocus;
29+
}
30+
}
31+
32+
export const createTaskStore = new CreateTaskStore();

src/screens/projects/components/TaskInput.tsx

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

src/screens/projects/components/observable/ObservableInput.ts

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

0 commit comments

Comments
 (0)