diff --git a/src/App.tsx b/src/App.tsx index 9646bf5c6f..1487ae9539 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,25 +1,116 @@ +import React, { useContext } from 'react'; +import { TodoList } from './components/TodoList'; + import './App.scss'; -// import usersFromServer from './api/users'; -// import todosFromServer from './api/todos'; +import { appContext } from './context/AppContext'; +import { getUserFrom } from './utils/getUser'; + +const allowedChars = /[а-яА-ЯІіЇїЄєҐґ'a-zA-Z0-9\s]+/; export const App = () => { + const { + query, + setQuery, + userId, + setUserId, + visibleTodos, + setVisibleTodos, + users, + userError, + setUserError, + inputError, + setInputError, + } = useContext(appContext); + + const handleInputOnChange = (e: React.ChangeEvent) => { + const { value } = e.target; + + if (!allowedChars.test(value) && value !== '') { + return; + } + + setQuery(value); + setInputError(''); + }; + + const handleUserOnChange = (e: React.ChangeEvent) => { + const { value } = e.target; + + setUserId(+value); + setUserError(''); + }; + + const handleSumbit = (e: React.FormEvent) => { + e.preventDefault(); + + if (!query.trim()) { + setInputError('Please enter a title'); + } + + if (!userId) { + setUserError('Please choose a user'); + } + + if (!userId || !query.trim()) { + return; + } + + const ids = visibleTodos.map((todo) => todo.id); + + const newTodo = { + id: Math.max(...ids) + 1, + title: query, + userId: +userId, + completed: false, + user: getUserFrom(+userId, users), + }; + + setVisibleTodos([...visibleTodos, newTodo]); + + setQuery(''); + setUserId(0); + }; + return (

Add todo form

-
+
- - Please enter a title + + {inputError}
- + - Please choose a user + {userError}
-
- - - - - -
+
); }; diff --git a/src/components/TodoInfo/TodoInfo.tsx b/src/components/TodoInfo/TodoInfo.tsx index d164511fa8..fdb9076d93 100644 --- a/src/components/TodoInfo/TodoInfo.tsx +++ b/src/components/TodoInfo/TodoInfo.tsx @@ -1 +1,24 @@ -export const TodoInfo = () => {}; +import React from 'react'; +import classNames from 'classnames'; +import { Todo } from '../../types/Todo'; +import { UserInfo } from '../UserInfo'; +import { User } from '../../types/User'; + +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..15f3581989 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..680d6b61f8 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'; + +type Props = { + user: User; +}; + +export const UserInfo: React.FC = ({ user }) => { + return ( + + {user.name} + + ); +}; diff --git a/src/context/AppContext.tsx b/src/context/AppContext.tsx new file mode 100644 index 0000000000..9cb841c52b --- /dev/null +++ b/src/context/AppContext.tsx @@ -0,0 +1,80 @@ +import React, { + ReactNode, createContext, useEffect, useState, +} from 'react'; + +import usersFromServer from '../api/users'; +import todosFromServer from '../api/todos'; +import { Todo } from '../types/Todo'; +import { User } from '../types/User'; + +type Props = { + children: ReactNode; +}; + +type AppContextType = { + query: string; + setQuery: React.Dispatch>; + userId: number; + setUserId: React.Dispatch>; + visibleTodos: Todo[]; + setVisibleTodos: React.Dispatch>; + inputError: string; + setInputError: React.Dispatch>; + userError: string; + setUserError: React.Dispatch>; + users: User[]; +}; + +const defaultContextValues: AppContextType = { + query: '', + setQuery: () => null, + userId: 0, + setUserId: () => null, + visibleTodos: [], + setVisibleTodos: () => null, + inputError: '', + setInputError: () => null, + userError: '', + setUserError: () => null, + users: [], +}; + +export const appContext = createContext(defaultContextValues); + +export const AppContextProvider: React.FC = ({ children }) => { + const [query, setQuery] = useState(''); + const [userId, setUserId] = useState(0); + const [visibleTodos, setVisibleTodos] = useState(todosFromServer); + const [users] = useState(usersFromServer); + const [inputError, setInputError] = useState(''); + const [userError, setUserError] = useState(''); + + useEffect(() => { + const todosWithUsers = visibleTodos.map((todo) => { + const todoWithUser: Todo = { + ...todo, + user: users.find((user) => user.id === todo.userId), + }; + + return todoWithUser; + }); + + setVisibleTodos(todosWithUsers); + }, []); + + const state = { + query, + setQuery, + userId, + setUserId, + visibleTodos, + setVisibleTodos, + inputError, + setInputError, + users, + userError, + setUserError, + }; + + return {children}; +}; diff --git a/src/index.tsx b/src/index.tsx index fbe940624e..6752924c72 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,4 +1,10 @@ import ReactDOM from 'react-dom'; import { App } from './App'; +import { AppContextProvider } from './context/AppContext'; -ReactDOM.render(, document.getElementById('root')); +ReactDOM.render( + + + , + document.getElementById('root'), +); 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..51c67d583b --- /dev/null +++ b/src/types/User.ts @@ -0,0 +1,6 @@ +export type User = { + id: number; + name: string; + email: string; + username: string; +}; diff --git a/src/utils/getUser.ts b/src/utils/getUser.ts new file mode 100644 index 0000000000..042f7ee3c6 --- /dev/null +++ b/src/utils/getUser.ts @@ -0,0 +1,5 @@ +import { User } from '../types/User'; + +export const getUserFrom = (userId: number, users: User[]) => { + return users.find((user) => user.id === userId); +};