Skip to content

Commit

Permalink
add task solution
Browse files Browse the repository at this point in the history
  • Loading branch information
kovaden414 committed Jan 6, 2025
1 parent 8d91581 commit 7e49e45
Show file tree
Hide file tree
Showing 4 changed files with 186 additions and 39 deletions.
133 changes: 97 additions & 36 deletions src/App.tsx
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>
);
};
33 changes: 32 additions & 1 deletion src/components/TodoInfo/TodoInfo.tsx
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>
);
};
38 changes: 37 additions & 1 deletion src/components/TodoList/TodoList.tsx
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>
);
};
21 changes: 20 additions & 1 deletion src/components/UserInfo/UserInfo.tsx
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>
);
})}
</>
);
};

0 comments on commit 7e49e45

Please sign in to comment.