From f0f36744634424dfcfba949854bd69ce9a987304 Mon Sep 17 00:00:00 2001 From: Yurii Mosin Date: Wed, 8 Jan 2025 15:10:50 +0100 Subject: [PATCH] add solution --- src/App.tsx | 133 ++++++++++++++++++++------- src/components/TodoInfo/TodoInfo.tsx | 24 ++++- src/components/TodoList/TodoList.tsx | 18 +++- src/components/UserInfo/UserInfo.tsx | 15 ++- src/types/Todo.ts | 8 ++ src/types/User.ts | 6 ++ 6 files changed, 167 insertions(+), 37 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 a9a9bb4c53..1de116f25c 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,27 +1,118 @@ +import { useState } from 'react'; import './App.scss'; +import usersFromServer from './api/users'; +import todosFromServer from './api/todos'; +import { TodoList } from './components/TodoList'; +import { Todo } from './types/Todo'; -// import usersFromServer from './api/users'; -// import todosFromServer from './api/todos'; +const findUserById = (userId: number) => { + return usersFromServer.find(user => user.id === userId); +}; + +const getPreparedTodos = () => { + return todosFromServer.map(todo => { + return { + ...todo, + user: findUserById(todo.userId) || null, + }; + }); +}; export const App = () => { + const [todos, setTodos] = useState(getPreparedTodos()); + const [selectedUserId, setSelectedUserId] = useState(0); + const [title, setTitle] = useState(''); + const [titleInputError, setTitleInputError] = useState(false); + const [userSelectError, setUserSelectError] = useState(false); + + const reset = () => { + setTitle(''); + setSelectedUserId(0); + setTitleInputError(false); + setUserSelectError(false); + }; + + function handleSubmit(event: React.FormEvent): void { + event.preventDefault(); + + setTitleInputError(!title); + setUserSelectError(!selectedUserId); + + if (!title || !selectedUserId) { + return; + } + + setTodos(currentTodos => { + const newId = Math.max(...currentTodos.map(todo => todo.id)) + 1; + + const user = findUserById(selectedUserId); + + const newTodo: Todo = { + id: newId, + title: title, + userId: selectedUserId, + completed: false, + user: user || null, + }; + + return [...currentTodos, newTodo]; + }); + + reset(); + } + + function handleTitleInput(event: React.ChangeEvent): void { + setTitle(event.target.value.trimStart()); + setTitleInputError(false); + } + + function handleUserSelect(event: React.ChangeEvent): void { + setSelectedUserId(Number(event.target.value)); + setUserSelectError(false); + } + return (

Add todo form

-
+
- - Please enter a title + + + {titleInputError && ( + Please enter a title + )}
- + + {usersFromServer.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..8b636b4a39 100644 --- a/src/components/TodoInfo/TodoInfo.tsx +++ b/src/components/TodoInfo/TodoInfo.tsx @@ -1 +1,23 @@ -export const TodoInfo = () => {}; +import React from 'react'; +import { Todo } from '../../types/Todo'; +import { UserInfo } from '../UserInfo'; +import classNames from 'classnames'; + +interface Props { + todo: Todo; +} + +export const TodoInfo: React.FC = ({ todo }) => { + return ( +
+

{todo.title}

+ + {todo.user && } +
+ ); +}; diff --git a/src/components/TodoList/TodoList.tsx b/src/components/TodoList/TodoList.tsx index c12fae07c0..09f6b500bd 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'; + +interface 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..71ee85e690 100644 --- a/src/components/UserInfo/UserInfo.tsx +++ b/src/components/UserInfo/UserInfo.tsx @@ -1 +1,14 @@ -export const UserInfo = () => {}; +import React from 'react'; +import { User } from '../../types/User'; + +interface Props { + user: User; +} + +export const UserInfo: React.FC = ({ user }) => { + return ( + + {user.name} + + ); +}; diff --git a/src/types/Todo.ts b/src/types/Todo.ts new file mode 100644 index 0000000000..2a52e192f6 --- /dev/null +++ b/src/types/Todo.ts @@ -0,0 +1,8 @@ +import { User } from './User'; +export interface Todo { + id: number; + title: string; + completed: boolean; + userId: number; + user: User | null; +} 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; +}