From bdc5eea0265db42c068d4002f013a17fbe0cdd80 Mon Sep 17 00:00:00 2001 From: Mykhailo Podaniev Date: Fri, 20 Feb 2026 12:12:28 +0200 Subject: [PATCH 01/20] add type definitions from previous versions --- src/types/ErrorMessages.ts | 9 +++++++++ src/types/Todo.ts | 6 ++++++ src/types/TodoFilter.ts | 1 + 3 files changed, 16 insertions(+) create mode 100644 src/types/ErrorMessages.ts create mode 100644 src/types/Todo.ts create mode 100644 src/types/TodoFilter.ts diff --git a/src/types/ErrorMessages.ts b/src/types/ErrorMessages.ts new file mode 100644 index 000000000..fa2dec70b --- /dev/null +++ b/src/types/ErrorMessages.ts @@ -0,0 +1,9 @@ +export const ERROR_MESSAGES = { + LOAD_FAIL: 'Unable to load todos', + EMPTY_TITLE: 'Title should not be empty', + ADD_FAIL: 'Unable to add a todo', + DELETE_FAIL: 'Unable to delete a todo', + UPDATE_FAIL: 'Unable to update a todo', +} as const; + +export type ErrorMessage = (typeof ERROR_MESSAGES)[keyof typeof ERROR_MESSAGES]; diff --git a/src/types/Todo.ts b/src/types/Todo.ts new file mode 100644 index 000000000..3f52a5fdd --- /dev/null +++ b/src/types/Todo.ts @@ -0,0 +1,6 @@ +export interface Todo { + id: number; + userId: number; + title: string; + completed: boolean; +} diff --git a/src/types/TodoFilter.ts b/src/types/TodoFilter.ts new file mode 100644 index 000000000..5d80905a9 --- /dev/null +++ b/src/types/TodoFilter.ts @@ -0,0 +1 @@ +export type TodoFilter = 'all' | 'active' | 'completed'; From dac8b81d8ca9dd8980e067dc59a5d1124a5b21a6 Mon Sep 17 00:00:00 2001 From: Mykhailo Podaniev Date: Fri, 20 Feb 2026 12:29:00 +0200 Subject: [PATCH 02/20] Show only a field to create a new todo --- src/App.tsx | 154 +++--------------------------------- src/components/Footer.tsx | 38 +++++++++ src/components/Header.tsx | 24 ++++++ src/components/TodoList.tsx | 4 + 4 files changed, 76 insertions(+), 144 deletions(-) create mode 100644 src/components/Footer.tsx create mode 100644 src/components/Header.tsx create mode 100644 src/components/TodoList.tsx diff --git a/src/App.tsx b/src/App.tsx index a399287bd..f13641b14 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,156 +1,22 @@ /* eslint-disable jsx-a11y/control-has-associated-label */ -import React from 'react'; +import React, { useState } from 'react'; +import { Header } from './components/Header'; +import { TodoList } from './components/TodoList'; +import { Footer } from './components/Footer'; +import { Todo } from './types/Todo'; export const App: React.FC = () => { + const [todos] = useState([]); + return (

todos

-
- {/* this button should have `active` class only if all todos are completed */} -
- -
- {/* This is a completed todo */} -
- - - - Completed Todo - - - {/* Remove button appears only on hover */} - -
- - {/* This todo is an active todo */} -
- - - - Not Completed Todo - - - -
- - {/* This todo is being edited */} -
- - - {/* This form is shown instead of the title and remove button */} -
- -
-
- - {/* This todo is in loadind state */} -
- - - - Todo is being saved now - - - -
-
- +
+ {/* Hide the footer if there are no todos */} -
- - 3 items left - - - {/* Active link should have the 'selected' class */} - - - {/* this button should be disabled if there are no completed todos */} - -
+ {todos.length > 0 &&
}
); diff --git a/src/components/Footer.tsx b/src/components/Footer.tsx new file mode 100644 index 000000000..67fdd0171 --- /dev/null +++ b/src/components/Footer.tsx @@ -0,0 +1,38 @@ + +export const Footer = () => { + return ( +
+ + 3 items left + + + {/* Active link should have the 'selected' class */} + + + {/* this button should be disabled if there are no completed todos */} + +
+ ); +}; diff --git a/src/components/Header.tsx b/src/components/Header.tsx new file mode 100644 index 000000000..5e73c5dd9 --- /dev/null +++ b/src/components/Header.tsx @@ -0,0 +1,24 @@ + + +export const Header = () => { + return ( +
+ {/* this button should have `active` class only if all todos are completed */} +
+ ); +}; diff --git a/src/components/TodoList.tsx b/src/components/TodoList.tsx new file mode 100644 index 000000000..45f65d615 --- /dev/null +++ b/src/components/TodoList.tsx @@ -0,0 +1,4 @@ + +export const TodoList = () => { + return
; +}; From b49d47b3271d212cbe5504b2f0eb9cee76fb975c Mon Sep 17 00:00:00 2001 From: Mykhailo Podaniev Date: Fri, 20 Feb 2026 18:17:40 +0200 Subject: [PATCH 03/20] add TodoContext with provider for managing todos --- src/context/TodoContext.tsx | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 src/context/TodoContext.tsx diff --git a/src/context/TodoContext.tsx b/src/context/TodoContext.tsx new file mode 100644 index 000000000..0df1b2a75 --- /dev/null +++ b/src/context/TodoContext.tsx @@ -0,0 +1,24 @@ +import React, { createContext, ReactNode, useState } from 'react'; +import { Todo } from '../types/Todo'; + +type TodoContextType = { + todos: Todo[]; + setTodos: React.Dispatch>; +}; + +const defaultContextValue: TodoContextType = { + todos: [], + setTodos: () => {}, +}; + +export const TodoContext = createContext(defaultContextValue); + +export const TodoProvider = ({ children }: { children: ReactNode }) => { + const [todos, setTodos] = useState([]); + + return ( + + {children} + + ); +}; From fdb2b19dc901dcf1ebd69471cac6543992d22e0e Mon Sep 17 00:00:00 2001 From: Mykhailo Podaniev Date: Fri, 20 Feb 2026 18:18:05 +0200 Subject: [PATCH 04/20] Show only a field to create a new todo --- src/App.tsx | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index f13641b14..325f00a16 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,12 +1,13 @@ /* eslint-disable jsx-a11y/control-has-associated-label */ -import React, { useState } from 'react'; +import React, { useContext } from 'react'; import { Header } from './components/Header'; import { TodoList } from './components/TodoList'; import { Footer } from './components/Footer'; -import { Todo } from './types/Todo'; +import { TodoContext } from './context/TodoContext'; export const App: React.FC = () => { - const [todos] = useState([]); + const { todos } = useContext(TodoContext); + const hasTodos = todos.length > 0; return (
@@ -14,9 +15,9 @@ export const App: React.FC = () => {
- + {hasTodos && } {/* Hide the footer if there are no todos */} - {todos.length > 0 &&
} + {hasTodos &&
}
); From d3d75342988f583894dc6c31fbfc85a6723a7d84 Mon Sep 17 00:00:00 2001 From: Mykhailo Podaniev Date: Fri, 20 Feb 2026 18:18:20 +0200 Subject: [PATCH 05/20] wrap App with TodoProvider in index.tsx --- src/index.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/index.tsx b/src/index.tsx index b2c38a17a..a4207b1fc 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -3,7 +3,12 @@ import { createRoot } from 'react-dom/client'; import './styles/index.scss'; import { App } from './App'; +import { TodoProvider } from './context/TodoContext'; const container = document.getElementById('root') as HTMLDivElement; -createRoot(container).render(); +createRoot(container).render( + + + , +); From a6aeede050edefe46f9528af36b517bc02541d2a Mon Sep 17 00:00:00 2001 From: Mykhailo Podaniev Date: Fri, 20 Feb 2026 18:18:34 +0200 Subject: [PATCH 06/20] remove unused userId field from Todo type definition --- src/types/Todo.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/types/Todo.ts b/src/types/Todo.ts index 3f52a5fdd..f9e06b381 100644 --- a/src/types/Todo.ts +++ b/src/types/Todo.ts @@ -1,6 +1,5 @@ export interface Todo { id: number; - userId: number; title: string; completed: boolean; } From 4c6aba722f495b9132185dc8b1359ff09d97088c Mon Sep 17 00:00:00 2001 From: Mykhailo Podaniev Date: Fri, 20 Feb 2026 18:18:55 +0200 Subject: [PATCH 07/20] remove unnecessary blank lines in component files --- src/components/Footer.tsx | 1 - src/components/Header.tsx | 2 -- src/components/TodoList.tsx | 1 - 3 files changed, 4 deletions(-) diff --git a/src/components/Footer.tsx b/src/components/Footer.tsx index 67fdd0171..6190f1ff4 100644 --- a/src/components/Footer.tsx +++ b/src/components/Footer.tsx @@ -1,4 +1,3 @@ - export const Footer = () => { return (