-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
8d91581
commit 7e49e45
Showing
4 changed files
with
186 additions
and
39 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,61 +1,122 @@ | ||
import './App.scss'; | ||
|
||
// import usersFromServer from './api/users'; | ||
// import todosFromServer from './api/todos'; | ||
import usersFromServer from './api/users'; | ||
import todosFromServer from './api/todos'; | ||
import { UserInfo } from './components/UserInfo'; | ||
import { TodoList } from './components/TodoList'; | ||
import { useState } from 'react'; | ||
|
||
type Todo = { | ||
id: number; | ||
title: string; | ||
userId: number; | ||
completed: boolean; | ||
}; | ||
|
||
export const App = ({}) => { | ||
const [todoList, setTodoList] = useState([...todosFromServer]); | ||
const [title, setTitle] = useState(''); | ||
const [userValue, setUserValue] = useState(0); | ||
const [inputError, setInputError] = useState(''); | ||
const [selectError, setSelectError] = useState(''); | ||
|
||
function getUserById(userId: number) { | ||
return usersFromServer.find(user => user.id === userId) || null; | ||
} | ||
|
||
const todos = todoList.map(todo => ({ | ||
...todo, | ||
user: getUserById(todo.userId), | ||
})); | ||
|
||
function getNewId(listOfTodos: Todo[]) { | ||
const maxId = Math.max(...listOfTodos.map(todo => todo.id)); | ||
|
||
return maxId + 1; | ||
} | ||
|
||
const handleInputError = (event: React.ChangeEvent<HTMLInputElement>) => { | ||
event.preventDefault(); | ||
setTitle(event.target.value); | ||
setInputError(''); | ||
}; | ||
|
||
const handleSelectError = (event: React.ChangeEvent<HTMLSelectElement>) => { | ||
event.preventDefault(); | ||
setUserValue(+event.target.value); | ||
setSelectError(''); | ||
}; | ||
|
||
const cleanForm = () => { | ||
setTitle(''); | ||
setUserValue(0); | ||
setInputError(''); | ||
setSelectError(''); | ||
}; | ||
|
||
const handleSubmit = (event: React.FormEvent) => { | ||
event.preventDefault(); | ||
|
||
const todo: Todo = { | ||
id: getNewId(todos), | ||
title: title, | ||
userId: userValue, | ||
completed: false, | ||
}; | ||
|
||
if (!title && !userValue) { | ||
setInputError('Please enter a title'); | ||
setSelectError('Please choose a user'); | ||
} else if (!title) { | ||
setInputError('Please enter a title'); | ||
} else if (!userValue) { | ||
setSelectError('Please choose a user'); | ||
} else { | ||
setTodoList([...todoList, todo]); | ||
cleanForm(); | ||
} | ||
}; | ||
|
||
export const App = () => { | ||
return ( | ||
<div className="App"> | ||
<h1>Add todo form</h1> | ||
|
||
<form action="/api/todos" method="POST"> | ||
<form action="/api/todos" method="POST" onSubmit={handleSubmit}> | ||
<div className="field"> | ||
<input type="text" data-cy="titleInput" /> | ||
<span className="error">Please enter a title</span> | ||
<label htmlFor="titleInput">Title: </label> | ||
<input | ||
type="text" | ||
data-cy="titleInput" | ||
placeholder="Enter a title" | ||
value={title} | ||
onChange={handleInputError} | ||
/> | ||
<span className="error">{inputError}</span> | ||
</div> | ||
|
||
<div className="field"> | ||
<select data-cy="userSelect"> | ||
<option value="0" disabled> | ||
<label htmlFor="userSelect">User: </label> | ||
<select | ||
data-cy="userSelect" | ||
value={userValue} | ||
onChange={handleSelectError} | ||
> | ||
<option value={0} disabled> | ||
Choose a user | ||
</option> | ||
|
||
<UserInfo users={usersFromServer} /> | ||
</select> | ||
|
||
<span className="error">Please choose a user</span> | ||
<span className="error">{selectError}</span> | ||
</div> | ||
|
||
<button type="submit" data-cy="submitButton"> | ||
Add | ||
</button> | ||
</form> | ||
|
||
<section className="TodoList"> | ||
<article data-id="1" className="TodoInfo TodoInfo--completed"> | ||
<h2 className="TodoInfo__title">delectus aut autem</h2> | ||
|
||
<a className="UserInfo" href="mailto:Sincere@april.biz"> | ||
Leanne Graham | ||
</a> | ||
</article> | ||
|
||
<article data-id="15" className="TodoInfo TodoInfo--completed"> | ||
<h2 className="TodoInfo__title">delectus aut autem</h2> | ||
|
||
<a className="UserInfo" href="mailto:Sincere@april.biz"> | ||
Leanne Graham | ||
</a> | ||
</article> | ||
|
||
<article data-id="2" className="TodoInfo"> | ||
<h2 className="TodoInfo__title"> | ||
quis ut nam facilis et officia qui | ||
</h2> | ||
|
||
<a className="UserInfo" href="mailto:Julianne.OConner@kory.org"> | ||
Patricia Lebsack | ||
</a> | ||
</article> | ||
</section> | ||
<TodoList todos={todos} /> | ||
</div> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,32 @@ | ||
export const TodoInfo = () => {}; | ||
import classNames from 'classnames'; | ||
|
||
type TodoInfoProps = { | ||
id: number; | ||
title: string; | ||
email: string; | ||
name: string; | ||
completed: boolean; | ||
}; | ||
|
||
export const TodoInfo = ({ | ||
id, | ||
title, | ||
email, | ||
name, | ||
completed, | ||
}: TodoInfoProps) => { | ||
return ( | ||
<article | ||
data-id={id} | ||
className={classNames('TodoInfo', { | ||
'TodoInfo--completed': completed, | ||
})} | ||
> | ||
<h2 className="TodoInfo__title">{title}</h2> | ||
|
||
<a className="UserInfo" href={`mailto:${email}`}> | ||
{name} | ||
</a> | ||
</article> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,37 @@ | ||
export const TodoList = () => {}; | ||
import { TodoInfo } from '../TodoInfo'; | ||
|
||
type Todo = { | ||
id: number; | ||
title: string; | ||
completed: boolean; | ||
userId: number; | ||
user: { | ||
id: number; | ||
name: string; | ||
username: string; | ||
email: string; | ||
} | null; | ||
}; | ||
|
||
export const TodoList = ({ todos }: { todos: Todo[] }) => { | ||
return ( | ||
<section className="TodoList"> | ||
{todos.map((todo: Todo) => { | ||
if (!todo.user) { | ||
return null; | ||
} | ||
|
||
return ( | ||
<TodoInfo | ||
id={todo.id} | ||
title={todo.title} | ||
email={todo.user.email} | ||
name={todo.user.name} | ||
completed={todo.completed} | ||
key={todo.id} | ||
/> | ||
); | ||
})} | ||
</section> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,20 @@ | ||
export const UserInfo = () => {}; | ||
type User = { | ||
id: number; | ||
name: string; | ||
username: string; | ||
email: string; | ||
}; | ||
|
||
export const UserInfo = ({ users }: { users: User[] }) => { | ||
return ( | ||
<> | ||
{users.map((user: User) => { | ||
return ( | ||
<option key={user.id} value={user.id}> | ||
{user.name} | ||
</option> | ||
); | ||
})} | ||
</> | ||
); | ||
}; |