diff --git a/src/App.tsx b/src/App.tsx index d46111e825..f1263611cb 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,5 +1,6 @@ /* eslint-disable max-len */ -import React from 'react'; + +import React, { useEffect, useState } from 'react'; import 'bulma/css/bulma.css'; import '@fortawesome/fontawesome-free/css/all.css'; @@ -7,8 +8,70 @@ 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 { getTodos, getUser } from './api'; +import { User } from './types/User'; +import { Field } from './types/FilterField'; export const App: React.FC = () => { + const [todos, setTodos] = useState([]); + const [isLoading, setIsLoading] = useState(false); + const [selectedTodo, setSelectedTodo] = useState(null); + const [user, setUser] = useState(null); + const [filteredField, setFilteredField] = useState(Field.All); + const [query, setQuery] = useState(''); + + const preparedTodos = todos.filter(todo => { + const filteredByField = (() => { + switch (filteredField) { + case Field.Completed: + return todo.completed; + case Field.Active: + return !todo.completed; + default: + return true; + } + })(); + + const filteredByQuery = query + ? todo.title.toLowerCase().includes(query.toLowerCase()) + : true; + + return filteredByField && filteredByQuery; + }); + + useEffect(() => { + setIsLoading(true); + + getTodos() + .then(setTodos) + .finally(() => setIsLoading(false)); + }, []); + + const handleTodo = (todo: Todo) => { + setIsLoading(true); + setSelectedTodo(todo); + + getUser(todo.userId) + .then(setUser) + .finally(() => setIsLoading(false)); + }; + + const handleChangeStatus = (newStatus: string) => { + setFilteredField(newStatus); + }; + + const handleChangeQuery = (event: React.ChangeEvent) => { + setQuery(event.target.value); + }; + + const onReset = () => { + setQuery(''); + setFilteredField(Field.All); + setSelectedTodo(null); + setUser(null); + }; + return ( <>
@@ -17,18 +80,33 @@ export const App: React.FC = () => {

Todos:

- +
- - + {isLoading && } +
- - + {selectedTodo && ( + + )} ); }; diff --git a/src/components/Todo/Todo.tsx b/src/components/Todo/Todo.tsx new file mode 100644 index 0000000000..a8b54d3e92 --- /dev/null +++ b/src/components/Todo/Todo.tsx @@ -0,0 +1,55 @@ +import classNames from 'classnames'; +import { Todo } from '../../types/Todo'; +import React from 'react'; + +type Props = { + todo: Todo; + selectedTodo: Todo | null; + showSelectedTodo: (todo: Todo) => void; +}; + +export const TodoItem: React.FC = props => { + const { todo, showSelectedTodo, selectedTodo } = props; + + const isSelectedTodo = todo.id === selectedTodo?.id; + + return ( + + {todo.id} + + {todo.completed && ( + + + + )} + + +

+ {todo.title} +

+ + + + + + ); +}; diff --git a/src/components/TodoFilter/TodoFilter.tsx b/src/components/TodoFilter/TodoFilter.tsx index 193f1cd2b2..8dd81ea446 100644 --- a/src/components/TodoFilter/TodoFilter.tsx +++ b/src/components/TodoFilter/TodoFilter.tsx @@ -1,8 +1,27 @@ -export const TodoFilter = () => ( +import classNames from 'classnames'; +import React from 'react'; +import { Field } from '../../types/FilterField'; + +type Props = { + query: string; + onChangeStatus: (newStatus: string) => void; + onChangeQuery: (event: React.ChangeEvent) => void; + onReset: () => void; +}; + +export const TodoFilter: React.FC = ({ + query, + onChangeStatus, + onChangeQuery, + onReset, +}) => (

- onChangeStatus(event.target.value)} + > @@ -16,15 +35,25 @@ export const TodoFilter = () => ( type="text" className="input" placeholder="Search..." + value={query} + onChange={onChangeQuery} /> - - {/* eslint-disable-next-line jsx-a11y/control-has-associated-label */} -