diff --git a/README.md b/README.md
index b8068748cc..7ab23b48ac 100644
--- a/README.md
+++ b/README.md
@@ -29,4 +29,4 @@ loaded and show them using `TodoList` (check the code in the `api.ts`);
- Implement a solution following the [React task guideline](https://github.com/mate-academy/react_task-guideline#react-tasks-guideline).
- Use the [React TypeScript cheat sheet](https://mate-academy.github.io/fe-program/js/extra/react-typescript).
- Open one more terminal and run tests with `npm test` to ensure your solution is correct.
-- Replace `` with your Github username in the [DEMO LINK](https://.github.io/react_dynamic-list-of-todos/) and add it to the PR description.
+- Replace `` with your Github username in the [DEMO LINK](https://dpidlutska.github.io/react_dynamic-list-of-todos/) and add it to the PR description.
diff --git a/src/App.tsx b/src/App.tsx
index d46111e825..ebc2eea82f 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,5 +1,5 @@
/* eslint-disable max-len */
-import React from 'react';
+import React, { useState, useEffect, useMemo } from 'react';
import 'bulma/css/bulma.css';
import '@fortawesome/fontawesome-free/css/all.css';
@@ -7,8 +7,34 @@ import { TodoList } from './components/TodoList';
import { TodoFilter } from './components/TodoFilter';
import { TodoModal } from './components/TodoModal';
import { Loader } from './components/Loader';
+import { Todo } from './types/Todo';
+import { TodosFilter } from './types/TodosFilter';
+import { getTodos } from './api';
+import { getPreparedTodos } from './services/todos';
export const App: React.FC = () => {
+ const [todos, setTodos] = useState([]);
+ const [query, setQuery] = useState('');
+ const [filter, setFilter] = useState(TodosFilter.All);
+ const [isLoading, setIsLoading] = useState(false);
+ const [selectedTodo, setSelectedTodo] = useState(null);
+
+ useEffect(() => {
+ setIsLoading(true);
+
+ getTodos()
+ .then(setTodos)
+ .catch(error => {
+ // eslint-disable-next-line no-console
+ console.log(error);
+ })
+ .finally(() => setIsLoading(false));
+ }, []);
+
+ const filteredTodos = useMemo(() => {
+ return getPreparedTodos(todos, query, filter);
+ }, [todos, query, filter]);
+
return (
<>
@@ -17,18 +43,37 @@ export const App: React.FC = () => {
Todos:
-
+
-
-
+ {isLoading
+ ? (
+
+ ) : (
+
+ )}
+
-
+ {selectedTodo && (
+
+ )}
>
);
};
diff --git a/src/components/TodoFilter/TodoFilter.tsx b/src/components/TodoFilter/TodoFilter.tsx
index c5ea5a5015..40d8c47067 100644
--- a/src/components/TodoFilter/TodoFilter.tsx
+++ b/src/components/TodoFilter/TodoFilter.tsx
@@ -1,34 +1,73 @@
-export const TodoFilter = () => (
-
-);
+
+
+
+
+
+ {query && (
+
+ )}
+
+
+
+ );
+};
diff --git a/src/components/TodoItem/TodoItem.tsx b/src/components/TodoItem/TodoItem.tsx
new file mode 100644
index 0000000000..e6a0971596
--- /dev/null
+++ b/src/components/TodoItem/TodoItem.tsx
@@ -0,0 +1,62 @@
+import React from 'react';
+import cn from 'classnames';
+import { Todo } from '../../types/Todo';
+
+type Props = {
+ todo: Todo;
+ selectedTodo: Todo | null;
+ onSelectTodo: (todo: Todo) => void;
+};
+
+export const TodoItem: React.FC = ({
+ todo,
+ selectedTodo,
+ onSelectTodo,
+}) => {
+ const { id, title, completed } = todo;
+ const isTodoSelected = selectedTodo === todo;
+
+ return (
+
+ {id} |
+
+ {completed && (
+
+
+
+ )}
+ |
+
+
+ {title}
+
+ |
+
+
+ |
+
+ );
+};
diff --git a/src/components/TodoItem/index.ts b/src/components/TodoItem/index.ts
new file mode 100644
index 0000000000..21f4abac39
--- /dev/null
+++ b/src/components/TodoItem/index.ts
@@ -0,0 +1 @@
+export * from './TodoItem';
diff --git a/src/components/TodoList/TodoList.tsx b/src/components/TodoList/TodoList.tsx
index 84dbcf3c0e..1b3649b145 100644
--- a/src/components/TodoList/TodoList.tsx
+++ b/src/components/TodoList/TodoList.tsx
@@ -1,6 +1,18 @@
import React from 'react';
+import { TodoItem } from '../TodoItem';
+import { Todo } from '../../types/Todo';
-export const TodoList: React.FC = () => (
+type Props = {
+ todos: Todo[];
+ selectedTodo: Todo | null;
+ onSelectTodo: (todo: Todo) => void;
+};
+
+export const TodoList: React.FC = ({
+ todos,
+ selectedTodo,
+ onSelectTodo,
+}) => (
@@ -16,85 +28,14 @@ export const TodoList: React.FC = () => (
-
- 1 |
- |
-
- delectus aut autem
- |
-
-
- |
-
-
- 2 |
- |
-
- quis ut nam facilis et officia qui
- |
-
-
- |
-
-
-
- 1 |
- |
-
- delectus aut autem
- |
-
-
- |
-
-
-
- 6 |
- |
-
-
- qui ullam ratione quibusdam voluptatem quia omnis
-
- |
-
-
- |
-
-
-
- 8 |
-
-
-
-
- |
-
- quo adipisci enim quam ut ab
- |
-
-
- |
-
+ {todos.map(todo => (
+
+ ))}
);
diff --git a/src/components/TodoModal/TodoModal.tsx b/src/components/TodoModal/TodoModal.tsx
index a1166885ca..cb75863e62 100644
--- a/src/components/TodoModal/TodoModal.tsx
+++ b/src/components/TodoModal/TodoModal.tsx
@@ -1,12 +1,37 @@
-import React from 'react';
+import React, { useState, useEffect } from 'react';
import { Loader } from '../Loader';
+import { Todo } from '../../types/Todo';
+import { User } from '../../types/User';
+import { getUser } from '../../api';
+
+type Props = {
+ selectedTodo: Todo | null;
+ onSelectTodo: (todo: Todo | null) => void;
+};
+
+export const TodoModal: React.FC = ({ selectedTodo, onSelectTodo }) => {
+ const [selectedUser, setSelectedUser] = useState(null);
+ const [loading, setLoading] = useState(false);
+
+ useEffect(() => {
+ setLoading(true);
+
+ if (selectedTodo) {
+ getUser(selectedTodo.userId)
+ .then(setSelectedUser)
+ .catch(error => {
+ // eslint-disable-next-line no-console
+ console.log(error);
+ })
+ .finally(() => setLoading(false));
+ }
+ }, []);
-export const TodoModal: React.FC = () => {
return (
- {true ? (
+ {loading ? (
) : (
@@ -15,30 +40,34 @@ export const TodoModal: React.FC = () => {
className="modal-card-title has-text-weight-medium"
data-cy="modal-header"
>
- Todo #2
+ {`Todo #${selectedTodo?.id}`}
- {/* eslint-disable-next-line jsx-a11y/control-has-associated-label */}