Skip to content

Commit

Permalink
add task solution
Browse files Browse the repository at this point in the history
  • Loading branch information
DimaDamage91 committed Jan 13, 2025
1 parent 3cfbf92 commit bf9d2c4
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 8 deletions.
3 changes: 3 additions & 0 deletions src/components/Footer/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ export const Footer: React.FC = () => {

setTodos(todosCompleted);
localStorage.setItem('todos', JSON.stringify(todosCompleted));

const inputField = document.querySelector(".todoapp__new-todo") as HTMLInputElement;
inputField!.focus();
};

return (
Expand Down
92 changes: 85 additions & 7 deletions src/components/TodoItem/TodoItem.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react';
import React, { useState, useRef } from 'react';
import { Todo } from '../../types/Todo';
import classNames from 'classnames';
import { useTodoContext } from '../../context/TodoContext';
Expand All @@ -8,7 +8,62 @@ interface Props {
}

export const TodoItem: React.FC<Props> = ({ todo }) => {
const { todos, setTodos } = useTodoContext();
const { todos, setTodos, newTitle, setNewTitle } = useTodoContext();
const [isEditForm, setIsEditForm] = useState(false);
const editInputRef = useRef<HTMLInputElement>(null);

const handleDoubleClick = () => {
setIsEditForm(true);
setNewTitle(todo.title);
setTimeout(() => {
editInputRef.current?.focus();
}, 0);
}

const editTitle = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();

const form = new FormData(e.currentTarget);
const newTitle = form.get('TodoTitleField') as string;

Check failure on line 27 in src/components/TodoItem/TodoItem.tsx

View workflow job for this annotation

GitHub Actions / run_linter (20.x)

'newTitle' is already declared in the upper scope on line 11 column 28

if (!newTitle.trim()) {
deleteTodo(todo.id);

Check failure on line 30 in src/components/TodoItem/TodoItem.tsx

View workflow job for this annotation

GitHub Actions / run_linter (20.x)

'deleteTodo' was used before it was defined
} else if (newTitle !== todo.title) {
editTodo(newTitle.trim(), todo.id);

Check failure on line 32 in src/components/TodoItem/TodoItem.tsx

View workflow job for this annotation

GitHub Actions / run_linter (20.x)

'editTodo' was used before it was defined
}

setTimeout(() => {
setIsEditForm(false);
}, 100);
};

const handleTitleBlur = (e: React.ChangeEvent<HTMLInputElement>) => {
const newTitle = e.target.value.trim();

Check failure on line 41 in src/components/TodoItem/TodoItem.tsx

View workflow job for this annotation

GitHub Actions / run_linter (20.x)

'newTitle' is already declared in the upper scope on line 11 column 28

if (!newTitle) {
deleteTodo(todo.id);

Check failure on line 44 in src/components/TodoItem/TodoItem.tsx

View workflow job for this annotation

GitHub Actions / run_linter (20.x)

'deleteTodo' was used before it was defined
return;
}

if (newTitle !== todo.title) {
editTodo(newTitle, todo.id);
}

Check failure on line 50 in src/components/TodoItem/TodoItem.tsx

View workflow job for this annotation

GitHub Actions / run_linter (20.x)

'editTodo' was used before it was defined

setIsEditForm(false);
};

const editTodo = (title: string, id: number) => {
const updatedTodos = todos.map(todo => todo.id === id ? { ...todo, title } : todo);

Check failure on line 57 in src/components/TodoItem/TodoItem.tsx

View workflow job for this annotation

GitHub Actions / run_linter (20.x)

'todo' is already declared in the upper scope on line 10 column 45
setTodos(updatedTodos);
localStorage.setItem('todos', JSON.stringify(updatedTodos));
};

const handleKeyUp = (e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === 'Escape') {
setIsEditForm(false);
}
};

const deleteTodo = (id: number) => {
const filteredTodos = todos.filter(todo => todo.id !== id);
Expand All @@ -30,7 +85,7 @@ export const TodoItem: React.FC<Props> = ({ todo }) => {
}

Check failure on line 85 in src/components/TodoItem/TodoItem.tsx

View workflow job for this annotation

GitHub Actions / run_linter (20.x)

'todo' is already declared in the upper scope on line 10 column 45

return (
<div data-cy="Todo" className={classNames("todo", {completed: todo.completed})}>
<div data-cy="Todo" className={classNames("todo", {completed: todo.completed})} onDoubleClick={handleDoubleClick}>
<label className="todo__status-label">
<input
data-cy="TodoStatus"
Expand All @@ -41,14 +96,37 @@ export const TodoItem: React.FC<Props> = ({ todo }) => {
/>
</label>

<span data-cy="TodoTitle" className="todo__title">
{todo.title}
</span>
{isEditForm ? (
<form onSubmit={editTitle}>
<input
data-cy="TodoTitleField"
type="text"
className="todo__title-field"
placeholder='What needs to be done?'
value={newTitle}
name="TodoTitleField"
ref={editInputRef}
onChange={(e) => setNewTitle(e.target.value)}
onBlur={handleTitleBlur}
onKeyUp={handleKeyUp}
/>
</form>
) : (
<span
data-cy="TodoTitle"
className="todo__title"
>
{todo.title}
</span>
)}


{/* Remove button appears only on hover */}
<button type="button" className="todo__remove" data-cy="TodoDelete" onClick={() => deleteTodo(todo.id)}>
{!isEditForm && (
<button type="button" className="todo__remove" data-cy="TodoDelete" onClick={() => deleteTodo(todo.id)} >
×
</button>
)}
</div>
)
}
9 changes: 8 additions & 1 deletion src/context/TodoContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ interface TodoContextType {
setTitle: (title: string) => void;
filter: 'all' | 'active' | 'completed';
setFilter: (filter: 'all' | 'active' | 'completed') => void;
newTitle: string;
setNewTitle: (editTitle: string) => void;
}

export const TodoContext = React.createContext<TodoContextType>({
Expand All @@ -18,6 +20,8 @@ export const TodoContext = React.createContext<TodoContextType>({
setTitle: () => {},
filter: 'all',
setFilter: () => {},
newTitle: '',
setNewTitle: () => {},
});

type Props = {
Expand All @@ -28,14 +32,17 @@ export const TodoProvider: React.FC<Props> = ({ children }) => {
const [ todos, setTodos ] = useState<Todo[]>([]);
const [ title, setTitle ] = useState<string>('');
const [ filter, setFilter ] = useState<FilterType>('all');
const [ newTitle, setNewTitle ] = useState<string>('');

const value: TodoContextType = {
todos,
setTodos,
title,
setTitle,
filter,
setFilter
setFilter,
newTitle,
setNewTitle,
}

return (
Expand Down

0 comments on commit bf9d2c4

Please sign in to comment.