diff --git a/README.md b/README.md
index b8068748cc..c3272d606f 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://DenysKolbasin.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..30135285fe 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,14 +1,42 @@
/* eslint-disable max-len */
-import React from 'react';
+import React, { useState, useEffect } from 'react';
import 'bulma/css/bulma.css';
import '@fortawesome/fontawesome-free/css/all.css';
import { TodoList } from './components/TodoList';
import { TodoFilter } from './components/TodoFilter';
-import { TodoModal } from './components/TodoModal';
import { Loader } from './components/Loader';
+import { getTodos } from './api';
+import { Todo } from './types/Todo';
+import { TodoModal } from './components/TodoModal';
+
+enum FilterStatus {
+ All = 'all',
+ Completed = 'completed',
+ Active = 'active',
+}
export const App: React.FC = () => {
+ const [todos, setTodos] = useState([]);
+ const [isLoading, setIsLoading] = useState(false);
+ const [selectedTodo, setSelectedTodo] = useState(null);
+ const [query, setQuery] = useState('');
+ const [status, setStatus] = useState(FilterStatus.All);
+
+ useEffect(() => {
+ setIsLoading(true);
+ getTodos()
+ .then(setTodos)
+ .finally(() => setIsLoading(false));
+ }, []);
+
+ const filteredTodos = todos.filter((todo) => (
+ (status === FilterStatus.All
+ || (status === FilterStatus.Completed && todo.completed)
+ || (status === FilterStatus.Active && !todo.completed))
+ && todo.title.toLowerCase().includes(query.toLowerCase())
+ ));
+
return (
<>
@@ -17,18 +45,36 @@ export const App: React.FC = () => {
Todos:
-
+
-
-
+ {isLoading && }
+
+ {!isLoading && filteredTodos.length > 0 && (
+
+ )}
-
-
+ {selectedTodo && (
+ setSelectedTodo(null)}
+ />
+ )}
>
);
};
diff --git a/src/api.ts b/src/api.ts
index 11b6f7280e..4f1fe41370 100644
--- a/src/api.ts
+++ b/src/api.ts
@@ -4,8 +4,6 @@ import { User } from './types/User';
// eslint-disable-next-line max-len
const BASE_URL = 'https://mate-academy.github.io/react_dynamic-list-of-todos/api';
-// This function creates a promise
-// that is resolved after a given delay
function wait(delay: number): Promise {
return new Promise(resolve => {
setTimeout(resolve, delay);
@@ -16,7 +14,6 @@ function get(url: string): Promise {
// eslint-disable-next-line prefer-template
const fullURL = BASE_URL + url + '.json';
- // we add some delay to see how the loader works
return wait(300)
.then(() => fetch(fullURL))
.then(res => res.json());
diff --git a/src/components/TodoFilter/TodoFilter.tsx b/src/components/TodoFilter/TodoFilter.tsx
index c5ea5a5015..179e9ffca8 100644
--- a/src/components/TodoFilter/TodoFilter.tsx
+++ b/src/components/TodoFilter/TodoFilter.tsx
@@ -1,34 +1,59 @@
-export const TodoFilter = () => (
-
-);
+
+
+
+
+ {query && (
+
+ {/* eslint-disable-next-line jsx-a11y/control-has-associated-label */}
+
+ )}
+
+
+ );
+};
diff --git a/src/components/TodoItem/TodoItem.tsx b/src/components/TodoItem/TodoItem.tsx
new file mode 100644
index 0000000000..b222101d09
--- /dev/null
+++ b/src/components/TodoItem/TodoItem.tsx
@@ -0,0 +1,62 @@
+import React from "react";
+import { Todo } from "../../types/Todo"
+import cn from 'classnames';
+
+
+interface Props {
+ todo: Todo;
+ onSelect?: (todo: Todo) => void;
+ selectedTodo: Todo | null;
+}
+
+export const TodoItem: React.FC = ({
+ todo,
+ onSelect,
+ selectedTodo,
+}) => {
+ return (
+
+ {todo.id} |
+
+ {todo.completed && (
+
+
+
+ )}
+ |
+
+
+ {todo.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..bc26c8188f 100644
--- a/src/components/TodoList/TodoList.tsx
+++ b/src/components/TodoList/TodoList.tsx
@@ -1,100 +1,42 @@
import React from 'react';
+import { Todo } from '../../types/Todo';
+import { TodoItem } from '../TodoItem';
-export const TodoList: React.FC = () => (
-
-
-
- # |
-
-
-
-
- |
- Title |
- |
-
-
+interface Props {
+ todos: Todo[];
+ onSelect?: (todo: Todo) => void;
+ selectedTodo: Todo | null;
+}
-
-
- 1 |
- |
-
- delectus aut autem
- |
-
- |
+ );
+};
diff --git a/src/components/TodoModal/TodoModal.tsx b/src/components/TodoModal/TodoModal.tsx
index a1166885ca..3af07c991b 100644
--- a/src/components/TodoModal/TodoModal.tsx
+++ b/src/components/TodoModal/TodoModal.tsx
@@ -1,12 +1,35 @@
-import React from 'react';
+import React, { useEffect, useState } from 'react';
import { Loader } from '../Loader';
+import { getUser } from '../../api';
+import { User } from '../../types/User';
+import { Todo } from '../../types/Todo';
+
+interface Props {
+ userId: number;
+ onClose: () => void;
+ selectedTodo: Todo | null;
+}
+
+export const TodoModal: React.FC = ({
+ userId,
+ onClose = () => { },
+ selectedTodo,
+}) => {
+ const [isLoading, setIsLoading] = useState(false);
+ const [user, setUser] = useState(null);
+
+ useEffect(() => {
+ setIsLoading(true);
+ getUser(userId)
+ .then(setUser)
+ .finally(() => setIsLoading(false));
+ }, [userId]);
-export const TodoModal: React.FC = () => {
return (
- {true ? (
+ {isLoading ? (
) : (
@@ -15,7 +38,8 @@ 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 */}
@@ -23,22 +47,26 @@ export const TodoModal: React.FC = () => {
type="button"
className="delete"
data-cy="modal-close"
+ onClick={onClose}
/>
- quis ut nam facilis et officia qui
+ {selectedTodo?.title}
- {/* Done */}
- Planned
+ {selectedTodo?.completed ? (
+ Done
+ ) : (
+ Planned
+ )}
{' by '}
-
- Leanne Graham
+
+ {user?.name}