Skip to content

Commit

Permalink
solution
Browse files Browse the repository at this point in the history
  • Loading branch information
YevhenRDoIT committed Dec 25, 2024
1 parent 8bf0f2b commit c8c8022
Show file tree
Hide file tree
Showing 5 changed files with 252 additions and 126 deletions.
36 changes: 31 additions & 5 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,26 @@
/* eslint-disable max-len */
import React from 'react';
import React, { useEffect, useState } from 'react';
import 'bulma/css/bulma.css';
import '@fortawesome/fontawesome-free/css/all.css';

import { TodoList } from './components/TodoList';
import { TodoFilter } from './components/TodoFilter';
import { TodoModal } from './components/TodoModal';
import { Loader } from './components/Loader';
import { Todo } from './types/Todo';

export const App: React.FC = () => {
const [isLoading, setIsLoading] = useState(true);
const [isModalVisible, setIsModalVisible] = useState(false);
const [todos, setTodos] = useState<Todo[] | null>(null);
const [todo, setTodo] = useState<Todo | null>(null);

useEffect(() => {
setTimeout(() => {
setIsLoading(false);
}, 1000);
}, []);

return (
<>
<div className="section">
Expand All @@ -17,18 +29,32 @@ export const App: React.FC = () => {
<h1 className="title">Todos:</h1>

<div className="block">
<TodoFilter />
<TodoFilter setTodos={setTodos} />
</div>

<div className="block">
<Loader />
<TodoList />
{isLoading ? (
<Loader />
) : (
<TodoList
setModalVisible={setIsModalVisible}
setSelectedTodo={setTodo}
todos={todos}
selectedTodo={todo}
/>
)}
</div>
</div>
</div>
</div>

<TodoModal />
{isModalVisible && (
<TodoModal
setVisible={setIsModalVisible}
todo={todo}
setTodo={setTodo}
/>
)}
</>
);
};
29 changes: 29 additions & 0 deletions src/api.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,32 @@
// import { Todo } from './types/Todo';
// import { User } from './types/User';

// // eslint-disable-next-line operator-linebreak
// const BASE_URL =
// 'https://mate-academy.github.io/react_dynamic-list-of-todos/api';

// // This function creates a promise
// // that is resolved after a given delay
// function wait(delay: number): Promise<void> {
// return new Promise(resolve => {
// setTimeout(resolve, delay);
// });
// }

// function get<T>(url: string): Promise<T> {
// // eslint-disable-next-line prefer-template
// const fullURL = BASE_URL + url + '.json';

// // we add some delay to see how the loader works
// return wait(300)
// .then(() => fetch(fullURL))
// .then(res => res.json());
// }

// export const getTodos = () => get<Todo[]>('/todos');

// export const getUser = (userId: number) => get<User>(`/users/${userId}`);

import { Todo } from './types/Todo';
import { User } from './types/User';

Expand Down
108 changes: 78 additions & 30 deletions src/components/TodoFilter/TodoFilter.tsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,78 @@
export const TodoFilter = () => (
<form className="field has-addons">
<p className="control">
<span className="select">
<select data-cy="statusSelect">
<option value="all">All</option>
<option value="active">Active</option>
<option value="completed">Completed</option>
</select>
</span>
</p>

<p className="control is-expanded has-icons-left has-icons-right">
<input
data-cy="searchInput"
type="text"
className="input"
placeholder="Search..."
/>
<span className="icon is-left">
<i className="fas fa-magnifying-glass" />
</span>

<span className="icon is-right" style={{ pointerEvents: 'all' }}>
{/* eslint-disable-next-line jsx-a11y/control-has-associated-label */}
<button data-cy="clearSearchButton" type="button" className="delete" />
</span>
</p>
</form>
);
import React, { useEffect, useState } from 'react';
import { Todo } from '../../types/Todo';
import { getTodos } from '../../api';

type Props = {
setTodos: React.Dispatch<React.SetStateAction<Todo[] | null>>;
};

export const TodoFilter: React.FC<Props> = ({ setTodos }) => {
const [qwerty, setQwerty] = useState('');
const [status, setStatus] = useState('');

useEffect(() => {
getTodos().then(serverTodos => {
let currentTodos: Todo[] | null = serverTodos.filter(todo =>
todo.title.toLocaleLowerCase().includes(qwerty.toLocaleLowerCase()),
);

switch (status) {
case 'active':
currentTodos = currentTodos.filter(todo => !todo.completed);
break;
case 'completed':
currentTodos = currentTodos.filter(todo => todo.completed);
break;
}

setTodos(currentTodos);
});
}, [qwerty, status, setTodos]);

return (
<form className="field has-addons">
<p className="control">
<span className="select">
<select
data-cy="statusSelect"
onChange={e => setStatus(e.target.value)}
>
<option value="all">All</option>
<option value="active">Active</option>
<option value="completed">Completed</option>
</select>
</span>
</p>

<p className="control is-expanded has-icons-left has-icons-right">
<input
data-cy="searchInput"
type="text"
className="input"
placeholder="Search..."
value={qwerty}
onChange={e => {
setQwerty(e.target.value);
}}
/>
<span className="icon is-left">
<i className="fas fa-magnifying-glass" />
</span>

<span className="icon is-right" style={{ pointerEvents: 'all' }}>
{/* eslint-disable-next-line jsx-a11y/control-has-associated-label */}
{qwerty && (
<button
data-cy="clearSearchButton"
type="button"
className="delete"
onClick={() => {
setQwerty('');
}}
/>
)}
</span>
</p>
</form>
);
};
150 changes: 68 additions & 82 deletions src/components/TodoList/TodoList.tsx
Original file line number Diff line number Diff line change
@@ -1,100 +1,86 @@
import React from 'react';
import { Todo } from '../../types/Todo';

export const TodoList: React.FC = () => (
<table className="table is-narrow is-fullwidth">
<thead>
<tr>
<th>#</th>
<th>
<span className="icon">
<i className="fas fa-check" />
</span>
</th>
<th>Title</th>
<th> </th>
</tr>
</thead>
type Props = {
todos: Todo[] | null;
setModalVisible: React.Dispatch<React.SetStateAction<boolean>>;
setSelectedTodo: React.Dispatch<React.SetStateAction<Todo | null>>;
selectedTodo: Todo | null;
};

<tbody>
<tr data-cy="todo" className="">
<td className="is-vcentered">1</td>
<td className="is-vcentered" />
<td className="is-vcentered is-expanded">
<p className="has-text-danger">delectus aut autem</p>
</td>
<td className="has-text-right is-vcentered">
<button data-cy="selectButton" className="button" type="button">
<span className="icon">
<i className="far fa-eye" />
</span>
</button>
</td>
</tr>
<tr data-cy="todo" className="has-background-info-light">
<td className="is-vcentered">2</td>
<td className="is-vcentered" />
<td className="is-vcentered is-expanded">
<p className="has-text-danger">quis ut nam facilis et officia qui</p>
</td>
<td className="has-text-right is-vcentered">
<button data-cy="selectButton" className="button" type="button">
<span className="icon">
<i className="far fa-eye-slash" />
</span>
</button>
</td>
</tr>
export const TodoList: React.FC<Props> = ({
setModalVisible,
todos,
setSelectedTodo,
selectedTodo,
}) => {
// console.log(todos);

<tr data-cy="todo" className="">
<td className="is-vcentered">1</td>
<td className="is-vcentered" />
<td className="is-vcentered is-expanded">
<p className="has-text-danger">delectus aut autem</p>
</td>
<td className="has-text-right is-vcentered">
<button data-cy="selectButton" className="button" type="button">
<span className="icon">
<i className="far fa-eye" />
function mapTodos() {
return todos?.map(todo => (
<tr
data-cy="todo"
className={
selectedTodo?.id === todo.id ? 'has-background-info-light' : undefined
}
key={todo.id}
>
<td className="is-vcentered">{todo.id}</td>
<td className="is-vcentered">
{todo.completed && (
<span className="icon" data-cy="iconCompleted">
<i className="fas fa-check" />
</span>
</button>
)}
</td>
</tr>

<tr data-cy="todo" className="">
<td className="is-vcentered">6</td>
<td className="is-vcentered" />
<td className="is-vcentered is-expanded">
<p className="has-text-danger">
qui ullam ratione quibusdam voluptatem quia omnis
<p
className={todo.completed ? 'has-text-success' : 'has-text-danger'}
>
{todo.title}
</p>
</td>
<td className="has-text-right is-vcentered">
<button data-cy="selectButton" className="button" type="button">
<button
data-cy="selectButton"
className="button"
type="button"
onClick={() => {
setModalVisible(true);
setSelectedTodo(todo);
}}
>
<span className="icon">
<i className="far fa-eye" />
<i
className={
selectedTodo && selectedTodo.id === todo.id
? 'far fa-eye-slash'
: 'far fa-eye'
}
/>
</span>
</button>
</td>
</tr>
));
}

<tr data-cy="todo" className="">
<td className="is-vcentered">8</td>
<td className="is-vcentered">
<span className="icon" data-cy="iconCompleted">
<i className="fas fa-check" />
</span>
</td>
<td className="is-vcentered is-expanded">
<p className="has-text-success">quo adipisci enim quam ut ab</p>
</td>
<td className="has-text-right is-vcentered">
<button data-cy="selectButton" className="button" type="button">
return (
<table className="table is-narrow is-fullwidth">
<thead>
<tr>
<th>#</th>
<th>
<span className="icon">
<i className="far fa-eye" />
<i className="fas fa-check" />
</span>
</button>
</td>
</tr>
</tbody>
</table>
);
</th>
<th>Title</th>
<th> </th>
</tr>
</thead>

<tbody>{mapTodos()}</tbody>
</table>
);
};
Loading

0 comments on commit c8c8022

Please sign in to comment.