Skip to content

Commit

Permalink
improve code
Browse files Browse the repository at this point in the history
  • Loading branch information
AlyonaV22 committed Dec 23, 2024
1 parent 6069bf9 commit 15c1d3c
Show file tree
Hide file tree
Showing 7 changed files with 123 additions and 155 deletions.
156 changes: 77 additions & 79 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState, useEffect } from 'react';
import React, { useState, useEffect, useCallback } from 'react';
import { UserWarning } from './UserWarning';
import {
addTodo,
Expand All @@ -16,13 +16,15 @@ import { TodoCard } from './commponents/TodoCard';
import { Todo } from './types/Todo';
import { Status } from './types/Status';
import { ErrorType } from './types/Errors';
import { LoadingTodo } from './types/LoadingTodo';
import { loadingTodo } from './utils/loadingTodo';

export const App: React.FC = () => {
const [todos, setTodos] = useState<Todo[]>([]);
const [filterType, setFilterType] = useState<Status>(Status.All);
const [errorType, setErrorType] = useState<ErrorType>(ErrorType.EmptyTitle);
const [tempTodo, setTempTodo] = useState<Todo | null>(null);
const [todoLoading, setTodoLoading] = useState<Loading>({});
const [todoLoading, setTodoLoading] = useState<LoadingTodo>({});

useEffect(() => {
const timeoutId = setTimeout(
Expand All @@ -32,6 +34,7 @@ export const App: React.FC = () => {

getTodos()
.then(setTodos)

.catch(() => {
setErrorType(ErrorType.UnableToLoad);
clearTimeout(timeoutId);
Expand All @@ -40,19 +43,6 @@ export const App: React.FC = () => {
return () => clearTimeout(timeoutId);
}, []);

interface Loading {
[key: number]: number;
}

const loadingTodo = (todoList: Todo[]): Loading => {
return todoList.reduce((acc: Loading, todo: Todo): Loading => {
return {
...acc,
[todo.id]: todo.id,
};
}, {} as Loading);
};

const todoFilter = todos.filter(todo => {
switch (filterType) {
case Status.Active:
Expand All @@ -64,59 +54,68 @@ export const App: React.FC = () => {
}
});

const addNewTodo = (todoToAdd: Todo): void => {
setTempTodo(todoToAdd);
const handleAddNewTodo = useCallback(
async (todoToAdd: Todo): Promise<void> => {
setTempTodo(todoToAdd);

try {
const todoNew = await addTodo(todoToAdd);

addTodo(todoToAdd)
.then(todoNew => {
setTodos(currentTodos => [...currentTodos, todoNew]);
})
.catch(() => {
} catch {
setErrorType(ErrorType.UnableToAdd);
})
.finally(() => {
} finally {
setTempTodo(null);
});
};
}
},
[setTodos, setTempTodo, setErrorType],
);

const deleteTodoItem = (todoId: number): void => {
deleteTodo(todoId)
.then(() => {
const handleDeleteTodo = useCallback(
async (todoId: number): Promise<void> => {
try {
await deleteTodo(todoId);
setTodos(currentTodos =>
currentTodos.filter(todo => todo.id !== todoId),
);
})
.catch(() => {
} catch {
setErrorType(ErrorType.UnableToDelete);
})
.finally(() => {
} finally {
setTempTodo(null);
});
};

const updateTodoItems = (
updateTodoItem: Todo,
key: keyof Todo,
value: boolean | string,
): Promise<boolean> => {
return updateTodo({ ...updateTodoItem, [key]: value })
.then(todoUpdated => {
}
},
[setTodos, setErrorType, setTempTodo],
);

const handleUpdateTodo = useCallback(
async (
updateTodoItem: Todo,
key: keyof Todo,
value: boolean | string,
): Promise<boolean> => {
try {
const todoUpdated = await updateTodo({
...updateTodoItem,
[key]: value,
});

setTodos(currentTodos =>
currentTodos.map(todo =>
todo.id === updateTodoItem.id ? todoUpdated : todo,
),
);

return false;
})
.catch(() => {
} catch {
setErrorType(ErrorType.UnableToUpdate);

return true;
});
};
}
},
[setTodos, setErrorType],
);

const loadedDeleteTodo = (): void => {
const removeCompletedTodos = useCallback(() => {
const completedTodos = todos.filter(todo => todo.completed);

setTodoLoading(loadingTodo(completedTodos));
Expand All @@ -138,43 +137,42 @@ export const App: React.FC = () => {
});
})
.finally(() => setTodoLoading({}));
};
}, [todos, setTodoLoading, setTodos, setErrorType]);

const handleAllCompleted = (): void => {
const completedAllTodos = (
const manageCompletedTodos = useCallback(async () => {
const completedAllTodos = async (
targetTodos: Todo[],
completed: boolean,
): Promise<void> => {
return Promise.all(
targetTodos.map(todo => updateTodo({ ...todo, completed })),
)
.then(() => {
setTodos(currentTodos =>
currentTodos.map(todo =>
targetTodos.some(t => t.id === todo.id)
? { ...todo, completed }
: todo,
),
);
})
.catch(() => {
setErrorType(ErrorType.UnableToUpdate);
})
.finally(() => {
setTodoLoading({});
});
) => {
try {
await Promise.all(
targetTodos.map(todo => updateTodo({ ...todo, completed })),
);

setTodos(currentTodos =>
currentTodos.map(todo =>
targetTodos.some(t => t.id === todo.id)
? { ...todo, completed }
: todo,
),
);
} catch {
setErrorType(ErrorType.UnableToUpdate);
} finally {
setTodoLoading({});
}
};

const activeTodos = todos.filter(todo => !todo.completed);

if (activeTodos.length) {
setTodoLoading(loadingTodo(activeTodos));
completedAllTodos(activeTodos, true);
await completedAllTodos(activeTodos, true);
} else {
setTodoLoading(loadingTodo(todos));
completedAllTodos(todos, false);
await completedAllTodos(todos, false);
}
};
}, [todos, setTodos, setErrorType, setTodoLoading]);

const lengthOfTodo = todos.length;

Expand All @@ -192,8 +190,8 @@ export const App: React.FC = () => {
setErrorType={setErrorType}
onChangeTodoTask={setTempTodo}
tempTodo={tempTodo}
addNewTodo={addNewTodo}
handleAllCompleted={handleAllCompleted}
onAddNewTodo={handleAddNewTodo}
manageCompletedTodos={manageCompletedTodos}
lengthOfTodo={lengthOfTodo}
/>

Expand All @@ -202,17 +200,17 @@ export const App: React.FC = () => {
<TodoCard
key={todo.id}
todo={todo}
deleteTodoItem={deleteTodoItem}
updateTodoItems={updateTodoItems}
handleDeleteTodo={handleDeleteTodo}
handleUpdateTodo={handleUpdateTodo}
todoLoading={todoLoading}
/>
))}

{tempTodo && (
<TodoCard
todo={tempTodo}
updateTodoItems={updateTodoItems}
deleteTodoItem={deleteTodoItem}
handleUpdateTodo={handleUpdateTodo}
handleDeleteTodo={handleDeleteTodo}
todoLoading={todoLoading}
/>
)}
Expand All @@ -223,7 +221,7 @@ export const App: React.FC = () => {
filterType={filterType}
onFiltered={setFilterType}
todos={todos}
loadedDeleteTodo={loadedDeleteTodo}
removeCompletedTodos={removeCompletedTodos}
setTodoLoading={setTodoLoading}
/>
)}
Expand Down
26 changes: 14 additions & 12 deletions src/commponents/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,38 @@ import React, { useMemo } from 'react';
import cn from 'classnames';
import { Status } from '../types/Status';
import { Todo } from '../types/Todo';

interface LoadingTodo {
[key: number]: number;
}
import { LoadingTodo } from '../types/LoadingTodo';

interface Props {
filterType: Status;
onFiltered: (filter: Status) => void;
todos: Todo[];
loadedDeleteTodo: () => void;
removeCompletedTodos: () => void;
setTodoLoading: React.Dispatch<React.SetStateAction<LoadingTodo>>;
}

export const Footer: React.FC<Props> = props => {
const { filterType, onFiltered, todos, loadedDeleteTodo, setTodoLoading } =
props;
const {
filterType,
onFiltered,
todos,
removeCompletedTodos,
setTodoLoading,
} = props;

const countTodo = useMemo(
() => todos.filter(todo => !todo.completed).length,
[todos],
);

const onTodoCompleted = useMemo(
() => todos.some(todo => todo.completed),
[todos],
);
const onTodoCompleted = todos.some(todo => todo.completed);

let onCompletedDelete = false;

const deleteCompletedTodo = () => {
setTodoLoading({});
onCompletedDelete = true;
loadedDeleteTodo();
removeCompletedTodos();
};

const filtersValue = useMemo(() => Object.values(Status), []);
Expand All @@ -43,6 +43,7 @@ export const Footer: React.FC<Props> = props => {
<span className="todo-count" data-cy="TodosCounter">
{countTodo} items left
</span>

<nav className="filter" data-cy="Filter">
{filtersValue.map(filter => (
<a
Expand All @@ -58,6 +59,7 @@ export const Footer: React.FC<Props> = props => {
</a>
))}
</nav>

<button
type="button"
className="todoapp__clear-completed"
Expand Down
19 changes: 11 additions & 8 deletions src/commponents/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useEffect, useRef, useState } from 'react';
import React, { useEffect, useRef, useState, useMemo } from 'react';
import { Todo } from '../types/Todo';
import { USER_ID } from '../api/todos';
import cn from 'classnames';
Expand All @@ -9,8 +9,8 @@ interface Props {
setErrorType: (errorType: ErrorType) => void;
onChangeTodoTask: (todoTask: Todo | null) => void;
tempTodo: Todo | null;
addNewTodo: (todo: Todo) => Promise<Todo | void>;
handleAllCompleted: () => void;
onAddNewTodo: (todo: Todo) => Promise<Todo | void>;
manageCompletedTodos: () => void;
lengthOfTodo: number;
}

Expand All @@ -20,16 +20,19 @@ export const Header: React.FC<Props> = props => {
setErrorType,
onChangeTodoTask,
tempTodo,
addNewTodo,
handleAllCompleted,
onAddNewTodo,
manageCompletedTodos,
lengthOfTodo,
} = props;

const [todoTask, setTodoTask] = useState('');

const todoUseRef = useRef<HTMLInputElement>(null);

const completedTodos = todos.every(todo => todo.completed);
const completedTodos = useMemo(
() => todos.every(todo => todo.completed),
[todos],
);

useEffect(() => {
if (todoUseRef.current && tempTodo === null) {
Expand All @@ -55,7 +58,7 @@ export const Header: React.FC<Props> = props => {

let hasNewTodo = true;

addNewTodo(itemTodo)
onAddNewTodo(itemTodo)
.catch(() => {
setErrorType(ErrorType.UnableToAdd);
hasNewTodo = false;
Expand All @@ -77,7 +80,7 @@ export const Header: React.FC<Props> = props => {
type="button"
className={cn('todoapp__toggle-all', { active: completedTodos })}
data-cy="ToggleAllButton"
onClick={handleAllCompleted}
onClick={manageCompletedTodos}
/>
)}

Expand Down
Loading

0 comments on commit 15c1d3c

Please sign in to comment.