diff --git a/src/components/Footer/Footer.tsx b/src/components/Footer/Footer.tsx index 620aac946..988b8e24c 100644 --- a/src/components/Footer/Footer.tsx +++ b/src/components/Footer/Footer.tsx @@ -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 ( diff --git a/src/components/TodoItem/TodoItem.tsx b/src/components/TodoItem/TodoItem.tsx index b32be88e8..2db636faf 100644 --- a/src/components/TodoItem/TodoItem.tsx +++ b/src/components/TodoItem/TodoItem.tsx @@ -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'; @@ -8,7 +8,62 @@ interface Props { } export const TodoItem: React.FC = ({ todo }) => { - const { todos, setTodos } = useTodoContext(); + const { todos, setTodos, newTitle, setNewTitle } = useTodoContext(); + const [isEditForm, setIsEditForm] = useState(false); + const editInputRef = useRef(null); + + const handleDoubleClick = () => { + setIsEditForm(true); + setNewTitle(todo.title); + setTimeout(() => { + editInputRef.current?.focus(); + }, 0); + } + + const editTitle = (e: React.FormEvent) => { + e.preventDefault(); + + const form = new FormData(e.currentTarget); + const newTitle = form.get('TodoTitleField') as string; + + if (!newTitle.trim()) { + deleteTodo(todo.id); + } else if (newTitle !== todo.title) { + editTodo(newTitle.trim(), todo.id); + } + + setTimeout(() => { + setIsEditForm(false); + }, 100); + }; + + const handleTitleBlur = (e: React.ChangeEvent) => { + const newTitle = e.target.value.trim(); + + if (!newTitle) { + deleteTodo(todo.id); + return; + } + + if (newTitle !== todo.title) { + editTodo(newTitle, todo.id); + } + + setIsEditForm(false); + }; + + const editTodo = (title: string, id: number) => { + const updatedTodos = todos.map(todo => todo.id === id ? { ...todo, title } : todo); + + setTodos(updatedTodos); + localStorage.setItem('todos', JSON.stringify(updatedTodos)); + }; + + const handleKeyUp = (e: React.KeyboardEvent) => { + if (e.key === 'Escape') { + setIsEditForm(false); + } + }; const deleteTodo = (id: number) => { const filteredTodos = todos.filter(todo => todo.id !== id); @@ -30,7 +85,7 @@ export const TodoItem: React.FC = ({ todo }) => { } return ( -
+
- - {todo.title} - + {isEditForm ? ( +
+ setNewTitle(e.target.value)} + onBlur={handleTitleBlur} + onKeyUp={handleKeyUp} + /> +
+ ) : ( + + {todo.title} + + )} + {/* Remove button appears only on hover */} - + )}
) } diff --git a/src/context/TodoContext.tsx b/src/context/TodoContext.tsx index a890f69b1..91d2aa1e2 100644 --- a/src/context/TodoContext.tsx +++ b/src/context/TodoContext.tsx @@ -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({ @@ -18,6 +20,8 @@ export const TodoContext = React.createContext({ setTitle: () => {}, filter: 'all', setFilter: () => {}, + newTitle: '', + setNewTitle: () => {}, }); type Props = { @@ -28,6 +32,7 @@ export const TodoProvider: React.FC = ({ children }) => { const [ todos, setTodos ] = useState([]); const [ title, setTitle ] = useState(''); const [ filter, setFilter ] = useState('all'); + const [ newTitle, setNewTitle ] = useState(''); const value: TodoContextType = { todos, @@ -35,7 +40,9 @@ export const TodoProvider: React.FC = ({ children }) => { title, setTitle, filter, - setFilter + setFilter, + newTitle, + setNewTitle, } return (