diff --git a/README.md b/README.md index f6e09d1094..76eb07abd9 100644 --- a/README.md +++ b/README.md @@ -25,4 +25,4 @@ Implement the ability to add TODOs to the `TodoList` implemented in the **Static - 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_add-todo-form/) and add it to the PR description. +- Replace `` with your Github username in the [DEMO LINK](https://Medaed.github.io/react_add-todo-form/) and add it to the PR description. diff --git a/src/App.scss b/src/App.scss index 9b9ddc979c..0653eedcb9 100644 --- a/src/App.scss +++ b/src/App.scss @@ -37,3 +37,9 @@ button { .UserInfo { font-style: italic; } + +.todo-list { + list-style: none; + + padding: 0; +} diff --git a/src/App.tsx b/src/App.tsx index 9646bf5c6f..a4fb6d4253 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,61 +1,135 @@ import './App.scss'; +import React, { useState } from 'react'; +import { TodoList } from './components/TodoList'; -// import usersFromServer from './api/users'; -// import todosFromServer from './api/todos'; +import usersFromServer from './api/users'; +import todosFromServer from './api/todos'; + +import { Todo } from './types/Todo'; + +function getUserById(userId: number) { + return usersFromServer.find(user => user.id === userId); +} + +function getTodoId(todos: Todo[]) { + const maxId = Math.max(...todos.map(todo => todo.id)); + + return maxId + 1; +} + +const initialTodos: Todo[] = todosFromServer.map(todo => ({ + ...todo, + user: getUserById(todo.userId), +})); + +export const App: React.FC = () => { + const [todos, setTodos] = useState(initialTodos); + + const [title, setTitle] = useState(''); + const [userId, setUserId] = useState(0); + + const [hasNoTitleError, setHasNoTitleError] = useState(true); + const [hasNoUserIdError, setHasNoUserIdError] = useState(true); + + const handleTitleChange = (event: React.ChangeEvent) => { + setTitle(event.target.value); + setHasNoTitleError(true); + }; + + const handleUserIdChange = (event: React.ChangeEvent) => { + setUserId(+event.target.value); + setHasNoUserIdError(true); + }; + + const addTodo = (event: React.FormEvent) => { + event.preventDefault(); + + let hasNoError = true; + + if (!title.trim()) { + setHasNoTitleError(false); + hasNoError = false; + } + + if (userId === 0) { + setHasNoUserIdError(false); + hasNoError = false; + } + + if (!hasNoError) { + return; + } + + const newTodo: Todo = { + id: getTodoId(todos), + title, + completed: false, + userId, + user: getUserById(userId), + }; + + setTodos([...todos, newTodo]); + + setTitle(''); + setUserId(0); + }; -export const App = () => { return (

Add todo form

-
+
- - Please enter a title + + {!hasNoTitleError && ( + Please enter a title + )}
- + + {usersFromServer.map(({ id, name }) => ( + + ))} - Please choose a user + {!hasNoUserIdError && ( + Please choose a user + )}
-
-
- - - - - -
+
); }; diff --git a/src/components/TodoInfo/TodoInfo.tsx b/src/components/TodoInfo/TodoInfo.tsx index d164511fa8..69ebb9ac2a 100644 --- a/src/components/TodoInfo/TodoInfo.tsx +++ b/src/components/TodoInfo/TodoInfo.tsx @@ -1 +1,34 @@ -export const TodoInfo = () => {}; +import cn from 'classnames'; +import { Todo } from '../../types/Todo'; +import { UserInfo } from '../UserInfo'; + +type Props = { + todo: Todo; +}; + +export const TodoInfo: React.FC = ({ todo }) => { + const { + id, + title, + completed, + user, + } = todo; + + return ( +
+

+ {title} +

+ + {user && ( + + )} +
+ ); +}; diff --git a/src/components/TodoList/TodoList.tsx b/src/components/TodoList/TodoList.tsx index c12fae07c0..27a2abf4fd 100644 --- a/src/components/TodoList/TodoList.tsx +++ b/src/components/TodoList/TodoList.tsx @@ -1 +1,21 @@ -export const TodoList = () => {}; +import React from 'react'; +import { Todo } from '../../types/Todo'; +import { TodoInfo } from '../TodoInfo'; + +type Props = { + todos: Todo[]; +}; + +export const TodoList: React.FC = ({ todos }) => { + return ( +
+
    + {todos.map(todo => ( +
  • + +
  • + ))} +
+
+ ); +}; diff --git a/src/components/UserInfo/UserInfo.tsx b/src/components/UserInfo/UserInfo.tsx index f7bf0410ec..3fe7996aa7 100644 --- a/src/components/UserInfo/UserInfo.tsx +++ b/src/components/UserInfo/UserInfo.tsx @@ -1 +1,16 @@ -export const UserInfo = () => {}; +import React from 'react'; +import { User } from '../../types/User'; + +type Props = { + user: User; +}; + +export const UserInfo: React.FC = ({ user }) => { + const { name, email } = user; + + return ( + + {name} + + ); +}; diff --git a/src/types/Todo.ts b/src/types/Todo.ts new file mode 100644 index 0000000000..48840cdec6 --- /dev/null +++ b/src/types/Todo.ts @@ -0,0 +1,9 @@ +import { User } from './User'; + +export type Todo = { + id: number; + title: string; + completed: boolean; + userId: number; + user?: User; +}; diff --git a/src/types/User.ts b/src/types/User.ts new file mode 100644 index 0000000000..f74409b994 --- /dev/null +++ b/src/types/User.ts @@ -0,0 +1,6 @@ +export type User = { + id: number; + name: string; + username: string; + email: string; +};