diff --git a/README.md b/README.md index 6226417010..22e33ad0a2 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://pti4ka121.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..bd25d74728 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": "^1.9.12", "@mate-academy/students-ts-config": "*", "@mate-academy/stylelint-config": "*", "@types/node": "^20.14.10", @@ -1170,9 +1170,9 @@ } }, "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": "1.9.12", + "resolved": "https://registry.npmjs.org/@mate-academy/scripts/-/scripts-1.9.12.tgz", + "integrity": "sha512-/OcmxMa34lYLFlGx7Ig926W1U1qjrnXbjFJ2TzUcDaLmED+A5se652NcWwGOidXRuMAOYLPU2jNYBEkKyXrFJA==", "dev": true, "dependencies": { "@octokit/rest": "^17.11.2", diff --git a/package.json b/package.json index 3cf9851f4f..eac8bda41c 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": "^1.9.12", "@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..2a0e35479a 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,61 +1,131 @@ import './App.scss'; -// import usersFromServer from './api/users'; -// import todosFromServer from './api/todos'; +import usersFromServer from './api/users'; +import todosFromServer from './api/todos'; +import { TodoList } from './components/TodoList'; +import React, { useState } from 'react'; +import { Todo, User } from './components/utils/types'; export const App = () => { + const getUserById = (userId: number): User | null => + usersFromServer.find(user => user.id === userId) || null; + + const initialTodos: Todo[] = todosFromServer.map(todo => ({ + ...todo, + user: getUserById(todo.userId), + })); + + const [userList] = useState(usersFromServer); + const [todosList, setTodosList] = useState(initialTodos); + + const [titleInput, setTitleInput] = useState(''); + const [userSelected, setUserSelected] = useState(''); + + const [titleInputError, setTitleInputError] = useState(false); + const [userSelectError, setUserSelectError] = useState(false); + + const receiveTheMaxId = () => { + const todoIds = todosList.map(todo => todo.id); + + return Math.max(...todoIds) + 1; + }; + + const createNewTodo = (): Todo => ({ + id: receiveTheMaxId(), + title: titleInput.trim(), + completed: false, + userId: +userSelected, + user: getUserById(+userSelected), + }); + + const handleSubmit = (event: React.FormEvent) => { + event.preventDefault(); + + let isValid = true; + + if (titleInput === '') { + setTitleInputError(true); + isValid = false; + } else { + setTitleInputError(false); + } + + if (userSelected === '') { + setUserSelectError(true); + isValid = false; + } else { + setUserSelectError(false); + } + + if (isValid) { + setTodosList(prevTodos => [...prevTodos, createNewTodo()]); + setTitleInput(''); + setUserSelected(''); + } + }; + + const handleSelectChange = (event: React.ChangeEvent) => { + setUserSelected(event.target.value); + + if (event.target.value !== '') { + setUserSelectError(false); + } + }; + + const validateTitleChange = (event: React.ChangeEvent) => { + const checkValues = event.target.value.replace(/[^a-zA-Zа-яА-Я0-9 ]/g, ''); + + setTitleInput(checkValues); + + if (checkValues !== '') { + setTitleInputError(false); + } + }; + return (

Add todo form

-
+
- - Please enter a title + + {titleInputError && ( + Please enter a title + )}
- + + {userList.map(user => ( + + ))} - Please choose a user + {userSelectError && ( + Please choose a user + )}
- -
- - - - - -
+
); }; diff --git a/src/components/TodoInfo/TodoInfo.tsx b/src/components/TodoInfo/TodoInfo.tsx index d164511fa8..e4f8937ed1 100644 --- a/src/components/TodoInfo/TodoInfo.tsx +++ b/src/components/TodoInfo/TodoInfo.tsx @@ -1 +1,22 @@ -export const TodoInfo = () => {}; +import classNames from 'classnames'; +import { Todo } from '../utils/types'; +import { UserInfo } from '../UserInfo'; + +type Props = { + todo: Todo; +}; + +export const TodoInfo: React.FC = ({ todo }) => { + return ( +
+

{todo.title}

+ + +
+ ); +}; diff --git a/src/components/TodoList/TodoList.tsx b/src/components/TodoList/TodoList.tsx index c12fae07c0..ba19d730af 100644 --- a/src/components/TodoList/TodoList.tsx +++ b/src/components/TodoList/TodoList.tsx @@ -1 +1,16 @@ -export const TodoList = () => {}; +import { TodoInfo } from '../TodoInfo'; +import { Todo } from '../utils/types'; + +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..07813444c3 100644 --- a/src/components/UserInfo/UserInfo.tsx +++ b/src/components/UserInfo/UserInfo.tsx @@ -1 +1,17 @@ -export const UserInfo = () => {}; +import { User } from '../utils/types'; + +type Props = { + user: User | null; +}; + +export const UserInfo: React.FC = ({ user }) => { + if (!user) { + return null; + } + + return ( + + {user.name} + + ); +}; diff --git a/src/components/utils/types.ts b/src/components/utils/types.ts new file mode 100644 index 0000000000..08d478c276 --- /dev/null +++ b/src/components/utils/types.ts @@ -0,0 +1,19 @@ +export type User = { + id: number; + name: string; + username: string; + email: string; +}; + +export type Todo = { + id: number; + title: string; + completed: boolean; + userId: number; + user: User | null; +}; + +export type TodoListProps = { + users: User[]; + todos: Todo[]; +};