This is a solution to the Todo app challenge on Frontend Mentor. Frontend Mentor challenges help you improve your coding skills by building realistic projects.
This is the front-end mentor's nineteen challenge. The challenge is to build the "Todo App" and make it as close to the design as possible. Building the desing with whatever you want to finish, any language, framework or tools.
Users should be able to:
- View the optimal layout for the app depending on their device's screen size
- See hover states for all interactive elements on the page
- Add new todos to the list
- Mark todos as complete
- Delete todos from the list
- Filter by all/active/complete todos
- Clear all completed todos
- Toggle light and dark mode
- Bonus: Drag and drop to reorder items on the list
- Solution URL: My solution for this challenge
- Live Site URL: check the result
- My figma design: Figma
- Mobile-first workflow
- typeScript
- React - JS library
- Styled components - CSS in js with stiled components
Criação de context usando typeScript
import React, { createContext, useContext, useEffect, useState } from 'react';
type TaskType = {
task: string;
isCompleted: boolean;
};
type PropsTaskContext = {
todos: TaskType[];
// eslint-disable-next-line no-unused-vars
addTodo: (newTodo: TaskType) => void;
// eslint-disable-next-line no-unused-vars
completeTodo: (e: TaskType) => void;
// eslint-disable-next-line no-unused-vars
removeTodo: (e: TaskType) => void;
// eslint-disable-next-line no-unused-vars
clearCompleted: () => void;
tagFilter: string;
// eslint-disable-next-line no-unused-vars
setTagFilter: (e: string) => void;
};
const DEFAULT_VALUE = {
todos: [
{
task: 'hello this is my todo App',
isCompleted: false,
},
],
// eslint-disable-next-line @typescript-eslint/no-empty-function
addTodo: () => {},
// eslint-disable-next-line @typescript-eslint/no-empty-function
completeTodo: () => {},
// eslint-disable-next-line @typescript-eslint/no-empty-function
removeTodo: () => {},
// eslint-disable-next-line @typescript-eslint/no-empty-function
clearCompleted: () => {},
tagFilter: 'all',
// eslint-disable-next-line @typescript-eslint/no-empty-function
setTagFilter: () => {},
};
const TaskContext = createContext<PropsTaskContext>(DEFAULT_VALUE);
const TaskProvider: React.FC = ({ children }) => {
const [todos, setTodos] = useState(DEFAULT_VALUE.todos);
const [tagFilter, setTagFilter] = useState('all');
const addTodo = (newTodo: TaskType) => {
setTodos((todos) => [...todos, newTodo]);
localStorage.setItem('todos', JSON.stringify([...todos, newTodo]));
};
const completeTodo = (e: TaskType) => {
const todo = e;
const restOfTodos = todos.map((value) => {
if (value.task !== todo.task) {
return value;
} else {
return value.isCompleted
? { task: value.task, isCompleted: false }
: { task: value.task, isCompleted: true };
}
});
setTodos(restOfTodos);
localStorage.setItem('todos', JSON.stringify(restOfTodos));
};
const removeTodo = (e: TaskType) => {
const todo = e;
const restOfTodos = todos.filter((value) => {
if (value.task !== todo.task) {
return value;
}
});
setTodos(restOfTodos);
localStorage.setItem('todos', JSON.stringify(restOfTodos));
};
const clearCompleted = () => {
const restOfTodos = todos.filter((value) => {
if (value.isCompleted === false) {
return value;
}
});
setTodos(restOfTodos);
localStorage.setItem('todos', JSON.stringify(restOfTodos));
};
useEffect(() => {
const hadTodos = localStorage.getItem('todos');
if (hadTodos) {
const localHistoric = JSON.parse(hadTodos);
setTodos(localHistoric);
}
}, []);
return (
<TaskContext.Provider
value={{
todos,
addTodo,
completeTodo,
removeTodo,
clearCompleted,
tagFilter,
setTagFilter,
}}
>
{children}
</TaskContext.Provider>
);
};
const TaskConsumer = (): PropsTaskContext => useContext(TaskContext);
export { TaskContext, TaskProvider, TaskConsumer };
Criação de um hook personalizado
import { useState } from 'react';
export const useTheme = (): [string, () => void] => {
const [theme, setTheme] = useState(localStorage.getItem('theme') || 'dark');
const saveSetTheme = (theme: string) => {
localStorage.setItem('theme', theme);
setTheme(theme);
};
const toggleTheme = (): void => {
theme === 'light' ? saveSetTheme('dark') : saveSetTheme('light');
};
return [theme, toggleTheme];
};
- react tutorial - This helped me structure the components and build the proposed page.
- my figma design - My figma design for help anyone who wants to build this challenge.
- CSS units conversor - px to VH/VW/REM - CSS units conversor .
- Converting Colors - HSL for all color systems.
- Personal Page - Jean Carlos De Meira
- Frontend Mentor - @JCDMeira
- Instagram - @jean.meira10
- GitHub - JCDMeira