From 4d7c1c19caa9a854bb878eaa7832fe93d31b5dca Mon Sep 17 00:00:00 2001 From: User Date: Sat, 18 Jan 2025 18:56:27 +0200 Subject: [PATCH 1/2] Solution --- src/App.tsx | 81 +++++++++-------------- src/components/NewTodo/NewTodo.tsx | 97 ++++++++++++++++++++++++++++ src/components/NewTodo/index.ts | 1 + src/components/TodoInfo/TodoInfo.tsx | 23 ++++++- src/components/TodoList/TodoList.tsx | 17 ++++- src/components/UserInfo/UserInfo.tsx | 14 +++- src/services/user.ts | 6 ++ src/types/ToDo.ts | 9 +++ src/types/User.ts | 6 ++ 9 files changed, 201 insertions(+), 53 deletions(-) create mode 100644 src/components/NewTodo/NewTodo.tsx create mode 100644 src/components/NewTodo/index.ts create mode 100644 src/services/user.ts 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..6a12fdf04d 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,61 +1,42 @@ import './App.scss'; -// import usersFromServer from './api/users'; -// import todosFromServer from './api/todos'; +import todosFromServer from './api/todos'; +import { TodoList } from './components/TodoList'; +import { NewTodo } from './components/NewTodo'; +import { getUserById } from './services/user'; +import { ToDo } from './types/ToDo'; +import { useState } from 'react'; + +const initialToDos: ToDo[] = todosFromServer.map(todo => ({ + ...todo, + user: getUserById(todo.userId), +})); + +function getNewToDoId(todos: ToDo[]) { + const maxId = Math.max(...todos.map(todo => todo.id)); + + return maxId + 1; +} export const App = () => { + const [todos, setTodos] = useState(initialToDos); + + const addToDo = (todo: Omit) => { + const newToDo = { + ...todo, + id: getNewToDoId(todos), + }; + + setTodos(currentToDos => [...currentToDos, newToDo]); + }; + return (

Add todo form

-
-
- - Please enter a title -
- -
- - - Please choose a user -
- - -
- -
- - - - - -
+ + +
); }; diff --git a/src/components/NewTodo/NewTodo.tsx b/src/components/NewTodo/NewTodo.tsx new file mode 100644 index 0000000000..434ab8c2e2 --- /dev/null +++ b/src/components/NewTodo/NewTodo.tsx @@ -0,0 +1,97 @@ +import { useState } from 'react'; + +import usersFromServer from '../../api/users'; +import { ToDo } from '../../types/ToDo'; +import { getUserById } from '../../services/user'; + +type Props = { + onAdd: (todo: Omit) => void; +}; + +export const NewTodo: React.FC = ({ onAdd }) => { + const [title, setTitle] = useState(''); + const [hasTitleError, setHasTitleError] = useState(false); + + const [userId, setUserId] = useState(0); + const [hasUserIdError, setHasUserIdError] = useState(false); + + const handleTitleChange = (event: React.ChangeEvent) => { + setTitle(event.target.value); + setHasTitleError(false); + }; + + const handleUserIdChange = (event: React.ChangeEvent) => { + setUserId(+event.target.value); + setHasUserIdError(false); + }; + + const handleReset = () => { + setTitle(''); + setUserId(0); + + setHasTitleError(false); + setHasUserIdError(false); + }; + + const handleSubmit = (event: React.FormEvent) => { + event.preventDefault(); + + setHasTitleError(!title); + setHasUserIdError(!userId); + + if (!title || !userId) { + return; + } + + onAdd({ + title, + userId, + user: getUserById(userId), + completed: false, + }); + + handleReset(); + }; + + return ( +
+
+ + + + {hasTitleError && Please enter a title} +
+ +
+ + + + {hasUserIdError && Please choose a user} +
+ + +
+ ); +}; diff --git a/src/components/NewTodo/index.ts b/src/components/NewTodo/index.ts new file mode 100644 index 0000000000..245c377cc2 --- /dev/null +++ b/src/components/NewTodo/index.ts @@ -0,0 +1 @@ +export * from './NewTodo'; diff --git a/src/components/TodoInfo/TodoInfo.tsx b/src/components/TodoInfo/TodoInfo.tsx index d164511fa8..e7c02bbbe4 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 '../../types/ToDo'; +import { UserInfo } from '../UserInfo'; + +type 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..d38c87cf5c 100644 --- a/src/components/TodoList/TodoList.tsx +++ b/src/components/TodoList/TodoList.tsx @@ -1 +1,16 @@ -export const TodoList = () => {}; +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..0451d18dfe 100644 --- a/src/components/UserInfo/UserInfo.tsx +++ b/src/components/UserInfo/UserInfo.tsx @@ -1 +1,13 @@ -export const UserInfo = () => {}; +import { User } from '../../types/User'; + +type Props = { + user: User; +}; + +export const UserInfo: React.FC = ({ user }) => { + return ( + + {user.name} + + ); +}; diff --git a/src/services/user.ts b/src/services/user.ts new file mode 100644 index 0000000000..95147dc88e --- /dev/null +++ b/src/services/user.ts @@ -0,0 +1,6 @@ +import { User } from '../types/User'; +import usersFromServer from '../api/users'; + +export function getUserById(userId: number): User | null { + return usersFromServer.find(user => user.id === userId) || null; +} diff --git a/src/types/ToDo.ts b/src/types/ToDo.ts new file mode 100644 index 0000000000..95b6a1eb93 --- /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 | 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; +} From 3643a64bb087aac6499fad71d5c0929b398558ef Mon Sep 17 00:00:00 2001 From: User Date: Sat, 18 Jan 2025 19:20:45 +0200 Subject: [PATCH 2/2] Solution --- src/App.tsx | 43 +++++----- src/components/NewTodo/NewTodo.tsx | 97 ---------------------- src/components/NewTodo/index.ts | 1 - src/components/TodoInfo/TodoInfo.tsx | 9 +-- src/components/TodoList/TodoList.tsx | 9 ++- src/components/UserInfo/UserInfo.tsx | 7 +- src/components/formPost/formPost.tsx | 115 +++++++++++++++++++++++++++ src/services/user.ts | 6 -- src/types/ToDo.ts | 9 --- src/types/User.ts | 6 -- src/types/types.tsx | 14 ++++ 11 files changed, 161 insertions(+), 155 deletions(-) delete mode 100644 src/components/NewTodo/NewTodo.tsx delete mode 100644 src/components/NewTodo/index.ts create mode 100644 src/components/formPost/formPost.tsx delete mode 100644 src/services/user.ts delete mode 100644 src/types/ToDo.ts delete mode 100644 src/types/User.ts create mode 100644 src/types/types.tsx diff --git a/src/App.tsx b/src/App.tsx index 6a12fdf04d..ec0138e3ae 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,41 +1,38 @@ +import React, { useState } from 'react'; import './App.scss'; +import usersFromServer from './api/users'; import todosFromServer from './api/todos'; import { TodoList } from './components/TodoList'; -import { NewTodo } from './components/NewTodo'; -import { getUserById } from './services/user'; -import { ToDo } from './types/ToDo'; -import { useState } from 'react'; +import { FormPost } from './components/formPost/formPost'; +import { ToDo, User } from './types/types'; -const initialToDos: ToDo[] = todosFromServer.map(todo => ({ +const getUser = (userId: number): User | null => { + return usersFromServer.find(user => user.id === userId) || null; +}; + +const initiaTodos: ToDo[] = todosFromServer.map(todo => ({ ...todo, - user: getUserById(todo.userId), + user: getUser(todo.userId), })); -function getNewToDoId(todos: ToDo[]) { - const maxId = Math.max(...todos.map(todo => todo.id)); - - return maxId + 1; -} +export const App: React.FC = () => { + const [todos, setTodos] = useState(initiaTodos); -export const App = () => { - const [todos, setTodos] = useState(initialToDos); + const highestId = Math.max(...todos.map(todo => todo.id)); - const addToDo = (todo: Omit) => { - const newToDo = { - ...todo, - id: getNewToDoId(todos), - }; - - setTodos(currentToDos => [...currentToDos, newToDo]); + const addPosts = (newToDo: ToDo) => { + setTodos(prev => [...prev, newToDo]); }; return (

Add todo form

- - - +
); diff --git a/src/components/NewTodo/NewTodo.tsx b/src/components/NewTodo/NewTodo.tsx deleted file mode 100644 index 434ab8c2e2..0000000000 --- a/src/components/NewTodo/NewTodo.tsx +++ /dev/null @@ -1,97 +0,0 @@ -import { useState } from 'react'; - -import usersFromServer from '../../api/users'; -import { ToDo } from '../../types/ToDo'; -import { getUserById } from '../../services/user'; - -type Props = { - onAdd: (todo: Omit) => void; -}; - -export const NewTodo: React.FC = ({ onAdd }) => { - const [title, setTitle] = useState(''); - const [hasTitleError, setHasTitleError] = useState(false); - - const [userId, setUserId] = useState(0); - const [hasUserIdError, setHasUserIdError] = useState(false); - - const handleTitleChange = (event: React.ChangeEvent) => { - setTitle(event.target.value); - setHasTitleError(false); - }; - - const handleUserIdChange = (event: React.ChangeEvent) => { - setUserId(+event.target.value); - setHasUserIdError(false); - }; - - const handleReset = () => { - setTitle(''); - setUserId(0); - - setHasTitleError(false); - setHasUserIdError(false); - }; - - const handleSubmit = (event: React.FormEvent) => { - event.preventDefault(); - - setHasTitleError(!title); - setHasUserIdError(!userId); - - if (!title || !userId) { - return; - } - - onAdd({ - title, - userId, - user: getUserById(userId), - completed: false, - }); - - handleReset(); - }; - - return ( -
-
- - - - {hasTitleError && Please enter a title} -
- -
- - - - {hasUserIdError && Please choose a user} -
- - -
- ); -}; diff --git a/src/components/NewTodo/index.ts b/src/components/NewTodo/index.ts deleted file mode 100644 index 245c377cc2..0000000000 --- a/src/components/NewTodo/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './NewTodo'; diff --git a/src/components/TodoInfo/TodoInfo.tsx b/src/components/TodoInfo/TodoInfo.tsx index e7c02bbbe4..5d3cb74e7f 100644 --- a/src/components/TodoInfo/TodoInfo.tsx +++ b/src/components/TodoInfo/TodoInfo.tsx @@ -1,6 +1,6 @@ -import classNames from 'classnames'; -import { ToDo } from '../../types/ToDo'; +import React from 'react'; import { UserInfo } from '../UserInfo'; +import { ToDo } from '../../types/types'; type Props = { todo: ToDo; @@ -10,12 +10,9 @@ 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 d38c87cf5c..f699589450 100644 --- a/src/components/TodoList/TodoList.tsx +++ b/src/components/TodoList/TodoList.tsx @@ -1,5 +1,6 @@ -import { ToDo } from '../../types/ToDo'; +import { ToDo } from '../../types/types'; import { TodoInfo } from '../TodoInfo'; +import React from 'react'; type Props = { todos: ToDo[]; @@ -8,9 +9,9 @@ type Props = { export const TodoList: React.FC = ({ todos }) => { return (
- {todos.map(todo => ( - - ))} + {todos.map(todo => { + return ; + })}
); }; diff --git a/src/components/UserInfo/UserInfo.tsx b/src/components/UserInfo/UserInfo.tsx index 0451d18dfe..11080c2be9 100644 --- a/src/components/UserInfo/UserInfo.tsx +++ b/src/components/UserInfo/UserInfo.tsx @@ -1,12 +1,13 @@ -import { User } from '../../types/User'; +import React from 'react'; +import { User } from '../../types/types'; type Props = { user: User; }; -export const UserInfo: React.FC = ({ user }) => { +export const UserInfo: React.FC = ({ user }: { user: User }) => { return ( - + {user.name} ); diff --git a/src/components/formPost/formPost.tsx b/src/components/formPost/formPost.tsx new file mode 100644 index 0000000000..54464afca0 --- /dev/null +++ b/src/components/formPost/formPost.tsx @@ -0,0 +1,115 @@ +import React, { useState } from 'react'; + +type User = { + id: number; + name: string; + username: string; + email: string; +}; + +type ToDo = { + id: number; + title: string; + completed: boolean; + userId: number | null; + user: User | null; +}; + +type Props = { + onSubmit: (newAdd: ToDo) => void; + users: User[]; + highestId: number; +}; + +export const FormPost: React.FC = ({ onSubmit, users, highestId }) => { + const [value, setValue] = useState(''); + const [touch, setTouch] = useState(false); + const [touchSelect, setTouchSelect] = useState(false); + const [select, setSelect] = useState(''); + const reset = (): void => { + setValue(''); + setSelect(''); + }; + + const handleChangeSelect = (e: React.ChangeEvent) => { + setSelect(e.currentTarget.value); + setTouchSelect(false); + }; + + const handleChangeInput = (e: React.ChangeEvent) => { + setValue(e.currentTarget.value); + if (e.currentTarget.value) { + setTouch(false); + } + }; + + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + + setTouch(!value); + setTouchSelect(!select); + + if (select && value) { + const foundUser: User | null = + users.find(user => user.name === select) || null; + + onSubmit({ + id: highestId + 1, + title: value, + completed: false, + userId: foundUser && foundUser.id, + user: foundUser, + }); + + reset(); + } + }; + + return ( +
handleSubmit(event)} + > +
+ + handleChangeInput(event)} + placeholder="Enter todo" + /> + + {touch && Please enter a title} +
+ +
+ + + {touchSelect && Please choose a user} +
+ + +
+ ); +}; diff --git a/src/services/user.ts b/src/services/user.ts deleted file mode 100644 index 95147dc88e..0000000000 --- a/src/services/user.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { User } from '../types/User'; -import usersFromServer from '../api/users'; - -export function getUserById(userId: number): User | null { - return usersFromServer.find(user => user.id === userId) || null; -} diff --git a/src/types/ToDo.ts b/src/types/ToDo.ts deleted file mode 100644 index 95b6a1eb93..0000000000 --- a/src/types/ToDo.ts +++ /dev/null @@ -1,9 +0,0 @@ -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 deleted file mode 100644 index 1f6908b55a..0000000000 --- a/src/types/User.ts +++ /dev/null @@ -1,6 +0,0 @@ -export interface User { - id: number; - name: string; - username: string; - email: string; -} diff --git a/src/types/types.tsx b/src/types/types.tsx new file mode 100644 index 0000000000..b9f3822a57 --- /dev/null +++ b/src/types/types.tsx @@ -0,0 +1,14 @@ +export type User = { + id: number; + name: string; + username: string; + email: string; +}; + +export type ToDo = { + id: number; + title: string; + completed: boolean; + userId: number | null; + user: User | null; +};