DEV Community

codetobuild
codetobuild

Posted on

1

TODO App with Reactjs - Beginners

Project folder structure

Image description

App component

import React from "react";
import Todo from "./components/Todo.component";

const App = () => {
  return <Todo />;
};

export default App;
Enter fullscreen mode Exit fullscreen mode

Todo Component

Image description

import { useState } from "react";
import "../styles/todo.css";
import TaskItem from "./TaskItem.component";

let taskId = 1;

const Todo = () => {
  const [inputText, setInputText] = useState("");
  const [tasks, setTasks] = useState([]);

  // function to update tasks state
  const updateTasks = (updatedTasks) => setTasks([...updatedTasks]);

  // function to handle addition of new tasks
  const handleAddTaskButtonClicked = (e) => {
    e.preventDefault();
    if (inputText.trim().length === 0) {
      return; // no need to add new tasks
    }
    taskId += 1;
    const newTask = {
      id: taskId,
      desc: inputText,
      status: {
        complete: false,
      },
    };

    // update state values
    updateTasks([...tasks, newTask]);
    setInputText("");
  };

  // control input element with component state
  const handleInputChange = (e) => {
    e.preventDefault();

    setInputText(() => e.target.value);
  };
  // add new task on enter key clicked
  const handleInputKeyDown = (e) => {
    const keycode = e.keyCode;
    // check is key pressed is enter key
    if (keycode === 13) {
      handleAddTaskButtonClicked(e);
    }
  };

  return (
    <div className="todo_wrapper">
      <h1 className="todo_header">TODO LIST</h1>
      <div className="todo_input_wrapper">
        <input
          className="todo_input_element"
          type="text"
          placeholder="What needs to be done?"
          value={inputText}
          onChange={handleInputChange}
          onKeyDown={handleInputKeyDown}
        />
        <button className="add_btn" onClick={handleAddTaskButtonClicked}>
          ADD
        </button>
      </div>
      <div className="tasks_wrapper">
        {tasks.map((taskItem, index) => (
          <TaskItem
            key={index}
            allTasks={tasks}
            updateTasks={updateTasks}
            taskItem={taskItem}
          />
        ))}
      </div>
    </div>
  );
};

export default Todo;
Enter fullscreen mode Exit fullscreen mode

TaskItem component

Image description

import React from "react";
import "../styles/todo.css";

const TaskItem = ({ updateTasks, allTasks, taskItem }) => {
  // function to handle tasks checkbox clicked
  const handleTaskCheckboxClicked = (e, taskItem) => {
    let updatedTasks = allTasks.map((elem) => {
      if (elem.id === taskItem.id) {
        elem.status.complete = !taskItem.status.complete; // toggle the status
      }
      return elem;
    });
    updateTasks(updatedTasks);
  };

  return (
    <li
      className={`task_item ${
        taskItem.status.complete === true ? "checked" : ""
      }`}
      key={taskItem.id}
    >
      <input
        type="checkbox"
        className="task_checkbox"
        onClick={(e) => handleTaskCheckboxClicked(e, taskItem)}
      />
      <p className="">{taskItem.desc}</p>
    </li>
  );
};

export default TaskItem;

Enter fullscreen mode Exit fullscreen mode

CSS code

.todo_wrapper {
  max-width: 600px;
  padding: 20px;
  background-color: rgb(55, 68, 95);
  margin: auto;
  margin-top: 50px;
  border-radius: 10px;
  box-shadow: 8px 13px 23px 0px rgba(0, 0, 0, 0.2);
}
.todo_header {
  color: white;
  text-align: center;
}
.todo_input_wrapper {
  display: flex;
  align-items: stretch;
}
.todo_input_element {
  flex-grow: 1;
  padding: 10px 10px;
  font-size: 1.1em;
  font-weight: 500;
  outline: none;
  border: none;
  border-radius: 5px 0 0 5px;
}
.add_btn {
  border: none;
  outline: none;
  padding: 0px 20px;
  font-size: 1.1em;
  font-weight: 700;
  background-color: lightgray;
  cursor: pointer;
  border-radius: 0 5px 5px 0;
}
.tasks_wrapper {
  padding: 20px 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.task_item {
  display: flex;
  gap: 10px;
  align-items: center;
  list-style-type: none;
  font-weight: 600;
  border-radius: 5px;
  background-color: lightgreen;
  padding: 10px 15px;
}

.task_item:hover {
  background-color: lime;
}

.task_item p {
  flex-grow: 1;
  margin: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.task_checkbox {
  position: relative;
  visibility: none;
  cursor: pointer;
  margin: 0;
}

.task_checkbox::before {
  content: "";
  font-weight: 800;
  width: 1.2em;
  height: 1.2em;
  background-color: white;
  border: 2px solid black;
  position: absolute;
  top: 0;
  left: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  transform: translate(-25%, -25%);
}

/* styles for task completed */
.task_item.checked {
  text-decoration: line-through;
  color: darkslategrey;
  background-color: lightslategray;
}
.task_item.checked:hover {
  background-color: lightgrey;
}

.task_item.checked .task_checkbox::before {
  content: "โœ“";
}

Enter fullscreen mode Exit fullscreen mode

Top comments (0)

The best way to debug slow web pages cover image

The best way to debug slow web pages

Tools like Page Speed Insights and Google Lighthouse are great for providing advice for front end performance issues. But what these tools canโ€™t do, is evaluate performance across your entire stack of distributed services and applications.

Watch video

๐Ÿ‘‹ Kindness is contagious

Please leave a โค๏ธ or a friendly comment on this post if you found it helpful!

Okay