Skip to content

Commit

Permalink
got some problem with loader
Browse files Browse the repository at this point in the history
  • Loading branch information
GlibVK committed Nov 6, 2024
1 parent afc7b23 commit b967a0e
Show file tree
Hide file tree
Showing 6 changed files with 272 additions and 168 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,4 @@ loaded and show them using `TodoList` (check the code in the `api.ts`);
- Implement a solution following the [React task guideline](https://github.com/mate-academy/react_task-guideline#react-tasks-guideline).
- Use the [React TypeScript cheat sheet](https://mate-academy.github.io/fe-program/js/extra/react-typescript).
- Open one more terminal and run tests with `npm test` to ensure your solution is correct.
- Replace `<your_account>` with your Github username in the [DEMO LINK](https://<your_account>.github.io/react_dynamic-list-of-todos/) and add it to the PR description.
- Replace `<your_account>` with your Github username in the [DEMO LINK](https://glibvk.github.io/react_dynamic-list-of-todos/) and add it to the PR description.
91 changes: 85 additions & 6 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,80 @@
/* 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 { getTodos, getUser } from './api';
import { Todo } from './types/Todo';
import { User } from './types/User';
import { Filter } from './types/enumFilter';

export const App: React.FC = () => {
const [user, setUser] = useState<User | null>(null);
const [todos, setTodos] = useState<Todo[]>([]);
const [todo, setTodo] = useState<Todo | null>(null);
const [loader, setLoader] = useState(true);
const [flag, setFlag] = useState(Filter.All);
const [modalLoad, setModalLoad] = useState(true);

useEffect(() => {
getTodos()
.then(fetchedTodos => {
setTodos(fetchedTodos);
})
.finally(() => setLoader(false));
}, []);

const getFilteredByFlag = (filterFlag: Filter) => {
switch (filterFlag) {
case Filter.All:
setFlag(Filter.All);
getTodos().then(setTodos);
break;
case Filter.Active:
setFlag(Filter.Active);
getTodos()
.then(fitchedTodos => fitchedTodos.filter(t => !t.completed))
.then(setTodos);
break;
case Filter.Completed:
getTodos()
.then(fetchTodos => fetchTodos.filter(t => t.completed))
.then(setTodos);
break;
default:
getTodos().then(setTodos);
break;
}
};

const getFilteredByValue = (value: string) => {
if (value.trim() !== '') {
setTodos(
todos.filter(t => t.title.toLowerCase().includes(value.toLowerCase())),
);
} else {
getFilteredByFlag(flag);
}
};

const getUserAndTodo = (todoUserId: number) => {
setModalLoad(true);

setTodo(todos.find(t => t.userId === todoUserId) || null);

getUser(todoUserId)
.then(setUser)
.finally(() => setModalLoad(false));
};

const handleCloseModal = () => {
setUser(null);
setTodo(null);
};

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

<div className="block">
<TodoFilter />
<TodoFilter
filterByFlag={getFilteredByFlag}
filteredByValue={getFilteredByValue}
/>
</div>

<div className="block">
<Loader />
<TodoList />
{loader ? (
<Loader />
) : (
<TodoList todos={todos} getUserAndTodo={getUserAndTodo} />
)}
</div>
</div>
</div>
</div>

<TodoModal />
{user && todo && (
<TodoModal
user={user}
todo={todo}
loader={modalLoad}
getClose={handleCloseModal}
/>
)}
</>
);
};
104 changes: 74 additions & 30 deletions src/components/TodoFilter/TodoFilter.tsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,74 @@
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 { useState } from 'react';
import { Filter } from '../../types/enumFilter';

type Props = {
filterByFlag: (value: Filter) => void;
filteredByValue: (value: string) => void;
};

export const TodoFilter: React.FC<Props> = ({
filterByFlag,
filteredByValue,
}) => {
const [showButton, setShowButton] = useState(false);
const [inputValue, setInputValue] = useState('');

const handleFilterByFlag = (e: React.ChangeEvent<HTMLSelectElement>) => {
filterByFlag(e.target.value as Filter);
};

const handleFilterByValue = (e: React.ChangeEvent<HTMLInputElement>) => {
setInputValue(e.target.value);
setShowButton(true);
filteredByValue(inputValue);

if (e.target.value === '') {
setShowButton(false);
}
};

const handleClearValue = () => {
setInputValue('');
setShowButton(false);
filteredByValue('');
};

return (
<form className="field has-addons">
<p className="control">
<span className="select">
<select data-cy="statusSelect" onChange={handleFilterByFlag}>
<option value={Filter.All}>All</option>
<option value={Filter.Active}>Active</option>
<option value={Filter.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..."
onChange={handleFilterByValue}
value={inputValue}
/>
<span className="icon is-left">
<i className="fas fa-magnifying-glass" />
</span>

{showButton && (
<span className="icon is-right" style={{ pointerEvents: 'all' }}>
<button
data-cy="clearSearchButton"
type="button"
className="delete"
onClick={() => handleClearValue()}
/>
</span>
)}
</p>
</form>
);
};
147 changes: 52 additions & 95 deletions src/components/TodoList/TodoList.tsx
Original file line number Diff line number Diff line change
@@ -1,100 +1,57 @@
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[];
getUserAndTodo: (todoUserId: number) => void;
};

<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">
export const TodoList: React.FC<Props> = ({ todos, getUserAndTodo }) => {
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>
<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>

<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="">
<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>
</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="">
<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">
<span className="icon">
<i className="far fa-eye" />
</span>
</button>
</td>
</tr>
</tbody>
</table>
);
</th>
<th>Title</th>
<th> </th>
</tr>
</thead>
<tbody>
{todos.map(todo => (
<tr data-cy="todo" className="" 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>
)}
</td>
<td className="is-vcentered is-expanded">
<p
className={`has-text-${todo.completed ? 'success' : 'danger'}`}
>
{todo.title}
</p>
</td>
<td className="has-text-right is-vcentered">
<button data-cy="selectButton" className="button" type="button">
<span
className="icon"
onClick={() => getUserAndTodo(todo.userId)}
>
<i className="far fa-eye" />
</span>
</button>
</td>
</tr>
))}
</tbody>
</table>
);
};
Loading

0 comments on commit b967a0e

Please sign in to comment.