diff --git a/README.md b/README.md index 2782426c5c..df278a8df4 100644 --- a/README.md +++ b/README.md @@ -30,4 +30,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://y-ivsnko.github.io/react_add-todo-form/) and add it to the PR description. diff --git a/package-lock.json b/package-lock.json index 8c9a76d958..5e76907ba8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,7 +18,7 @@ }, "devDependencies": { "@cypress/react18": "^2.0.1", - "@mate-academy/scripts": "^1.8.5", + "@mate-academy/scripts": "^2.1.3", "@mate-academy/students-ts-config": "*", "@mate-academy/stylelint-config": "*", "@types/node": "^20.14.10", @@ -1170,10 +1170,11 @@ } }, "node_modules/@mate-academy/scripts": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/@mate-academy/scripts/-/scripts-1.8.5.tgz", - "integrity": "sha512-mHRY2FkuoYCf5U0ahIukkaRo5LSZsxrTSgMJheFoyf3VXsTvfM9OfWcZIDIDB521kdPrScHHnRp+JRNjCfUO5A==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@mate-academy/scripts/-/scripts-2.1.3.tgz", + "integrity": "sha512-a07wHTj/1QUK2Aac5zHad+sGw4rIvcNl5lJmJpAD7OxeSbnCdyI6RXUHwXhjF5MaVo9YHrJ0xVahyERS2IIyBQ==", "dev": true, + "license": "MIT", "dependencies": { "@octokit/rest": "^17.11.2", "@types/get-port": "^4.2.0", diff --git a/package.json b/package.json index 3cf9851f4f..756d7400ab 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ }, "devDependencies": { "@cypress/react18": "^2.0.1", - "@mate-academy/scripts": "^1.8.5", + "@mate-academy/scripts": "^2.1.3", "@mate-academy/students-ts-config": "*", "@mate-academy/stylelint-config": "*", "@types/node": "^20.14.10", diff --git a/src/App.tsx b/src/App.tsx index a9a9bb4c53..84d6f63072 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,27 +1,114 @@ +import { FormEvent, useState } from 'react'; import './App.scss'; +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'; +import { User } from './types/User'; + +function getUserById(userId: number): User { + const user = usersFromServer.find(preson => preson.id === userId); + + if (!user) { + throw new Error(`User with id ${userId} was not found`); + } + + return user; +} export const App = () => { + const [title, setTitle] = useState(''); + const [titleError, setTitleError] = useState(false); + const [selectedUserId, setSelectedUserId] = useState(''); + const [userError, setUserError] = useState(false); + const [todos, setTodos] = useState( + todosFromServer.map(todo => ({ + ...todo, + user: getUserById(todo.userId), + })), + ); + + const handleSubmit = (event: FormEvent) => { + event.preventDefault(); + + const hasTitle = title.trim().length > 0; + const hasSelectedUser = selectedUserId !== ''; + + if (!hasTitle) { + setTitleError(true); + } + + if (!hasSelectedUser) { + setUserError(true); + } + + if (!hasTitle || !hasSelectedUser) { + return; + } + + const userId = +selectedUserId; + const user = getUserById(userId); + const maxTodoId = + todos.length > 0 ? Math.max(...todos.map(todo => todo.id)) : 0; + + const newTodo: Todo = { + id: maxTodoId + 1, + title: title.trim(), + userId, + completed: false, + user, + }; + + setTodos(currentTodos => [...currentTodos, newTodo]); + setTitle(''); + setSelectedUserId(''); + setTitleError(false); + setUserError(false); + }; + return (

Add todo form

-
+
- - Please enter a title + + { + setTitle(event.target.value); + setTitleError(false); + }} + /> + {titleError && Please enter a title}
- { + setSelectedUserId(event.target.value); + setUserError(false); + }} + > + + {usersFromServer.map(user => ( + + ))} - Please choose a user + {userError && Please choose a user}
-
- - - - - -
+
); }; diff --git a/src/components/TodoInfo/TodoInfo.tsx b/src/components/TodoInfo/TodoInfo.tsx index d164511fa8..47971ea822 100644 --- a/src/components/TodoInfo/TodoInfo.tsx +++ b/src/components/TodoInfo/TodoInfo.tsx @@ -1 +1,23 @@ -export const TodoInfo = () => {}; +import { UserInfo } from '../../components/UserInfo'; +import { Todo } from '../../types/todo'; +import classNames from 'classnames'; + +type Props = { + todo: Todo; +}; + +export const TodoInfo = ({ todo }: Props) => { + return ( +
+

{todo.title}

+ + +
+ ); +}; diff --git a/src/components/TodoList/TodoList.tsx b/src/components/TodoList/TodoList.tsx index c12fae07c0..a74785035c 100644 --- a/src/components/TodoList/TodoList.tsx +++ b/src/components/TodoList/TodoList.tsx @@ -1 +1,14 @@ -export const TodoList = () => {}; +import { Todo } from '../../types/todo'; +import { TodoInfo } from '../TodoInfo'; + +interface Props { + todos: Todo[]; +} + +export const TodoList = ({ todos }: Props) => ( +
+ {todos.map(todo => ( + + ))} +
+); diff --git a/src/components/UserInfo/UserInfo.tsx b/src/components/UserInfo/UserInfo.tsx index f7bf0410ec..61799d0eca 100644 --- a/src/components/UserInfo/UserInfo.tsx +++ b/src/components/UserInfo/UserInfo.tsx @@ -1 +1,13 @@ -export const UserInfo = () => {}; +import { User } from '../../types/User'; + +interface Props { + user: User; +} + +export const UserInfo = ({ user }: Props) => { + return ( + + {user.name} + + ); +}; diff --git a/src/types/Todo.ts b/src/types/Todo.ts new file mode 100644 index 0000000000..ab2c147d8d --- /dev/null +++ b/src/types/Todo.ts @@ -0,0 +1,9 @@ +import { User } from './User'; + +export interface 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..1f6908b55a --- /dev/null +++ b/src/types/User.ts @@ -0,0 +1,6 @@ +export interface User { + id: number; + name: string; + username: string; + email: string; +}