From 1e154544c5d02e3a8365acf2fdec6c656e024fa2 Mon Sep 17 00:00:00 2001 From: M DD Date: Mon, 6 Nov 2023 16:29:32 +0200 Subject: [PATCH 1/3] react_add-todo-form solution v1 --- src/App.tsx | 147 ++++++++++++++++++++------- src/components/TodoInfo/TodoInfo.tsx | 36 ++++++- src/components/TodoList/TodoList.tsx | 18 +++- src/components/UserInfo/UserInfo.tsx | 17 +++- src/types/Todo.ts | 9 ++ src/types/User.ts | 6 ++ 6 files changed, 191 insertions(+), 42 deletions(-) create mode 100644 src/types/Todo.ts create mode 100644 src/types/User.ts diff --git a/src/App.tsx b/src/App.tsx index 9646bf5c6f..d346901573 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,61 +1,130 @@ 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(); + + if (!title.trim()) { + setHasNoTitleError(false); + + return; + } + + if (userId === 0) { + setHasNoUserIdError(false); + + return; + } + + const newTodo: Todo = { + id: getTodoId(todos), + title, + completed: false, + userId, + user: usersFromServer.find(user => user.id === 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(user => ( + + ))} - 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..67b09cef31 100644 --- a/src/components/TodoInfo/TodoInfo.tsx +++ b/src/components/TodoInfo/TodoInfo.tsx @@ -1 +1,35 @@ -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..f76f09bf18 100644 --- a/src/components/TodoList/TodoList.tsx +++ b/src/components/TodoList/TodoList.tsx @@ -1 +1,17 @@ -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; +}; From f42663ac24add89bb37ba19ddf7fef6b8a079792 Mon Sep 17 00:00:00 2001 From: M DD Date: Tue, 7 Nov 2023 01:12:18 +0200 Subject: [PATCH 2/3] react_add-todo-form solution v2 --- README.md | 2 +- src/App.scss | 6 ++++++ src/App.tsx | 17 +++++++++++------ src/components/TodoList/TodoList.tsx | 10 +++++++--- 4 files changed, 25 insertions(+), 10 deletions(-) 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 d346901573..475e2cec51 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -27,6 +27,7 @@ export const App: React.FC = () => { const [title, setTitle] = useState(''); const [userId, setUserId] = useState(0); + const [hasNoTitleError, setHasNoTitleError] = useState(true); const [hasNoUserIdError, setHasNoUserIdError] = useState(true); @@ -43,15 +44,19 @@ export const App: React.FC = () => { const addTodo = (event: React.FormEvent) => { event.preventDefault(); + let hasNoError = true; + if (!title.trim()) { setHasNoTitleError(false); - - return; + hasNoError = false; } if (userId === 0) { setHasNoUserIdError(false); + hasNoError = false; + } + if (!hasNoError) { return; } @@ -101,12 +106,12 @@ export const App: React.FC = () => { - {usersFromServer.map(user => ( + {usersFromServer.map(({ id, name }) => ( ))} diff --git a/src/components/TodoList/TodoList.tsx b/src/components/TodoList/TodoList.tsx index f76f09bf18..27a2abf4fd 100644 --- a/src/components/TodoList/TodoList.tsx +++ b/src/components/TodoList/TodoList.tsx @@ -9,9 +9,13 @@ type Props = { export const TodoList: React.FC = ({ todos }) => { return (
- {todos.map(todo => ( - - ))} +
    + {todos.map(todo => ( +
  • + +
  • + ))} +
); }; From 16a9fdf14c5113e9f5a13f283c67ba89124c61f6 Mon Sep 17 00:00:00 2001 From: M DD Date: Tue, 7 Nov 2023 12:11:52 +0200 Subject: [PATCH 3/3] react_add-todo-form solution v3 --- src/App.tsx | 4 ++-- src/components/TodoInfo/TodoInfo.tsx | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index 475e2cec51..a4fb6d4253 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -65,7 +65,7 @@ export const App: React.FC = () => { title, completed: false, userId, - user: usersFromServer.find(user => user.id === userId), + user: getUserById(userId), }; setTodos([...todos, newTodo]); @@ -109,7 +109,7 @@ export const App: React.FC = () => { {usersFromServer.map(({ id, name }) => ( diff --git a/src/components/TodoInfo/TodoInfo.tsx b/src/components/TodoInfo/TodoInfo.tsx index 67b09cef31..69ebb9ac2a 100644 --- a/src/components/TodoInfo/TodoInfo.tsx +++ b/src/components/TodoInfo/TodoInfo.tsx @@ -27,7 +27,6 @@ export const TodoInfo: React.FC = ({ todo }) => { {user && ( - )}