Skip to content

Mark Item as Done

We will repeat the same process as for the remove button for our checkbox, it is 99% similar approach. We add a new function that will dispatch markItemAsDone action and we pass it to our List.tsx.

import { useDispatch, useSelector } from "react-redux";
import ListHeader from "../components/ListHeader";
import List from "../components/List";
import { addItem, markItemAsDone, removeItem } from "../store/actions/todo";
import { useState } from "react";
import { RootState } from "../store/reducers";

function App() {
    const dispatch = useDispatch();
    const [title, setTitle] = useState<string>("");

    const todo = useSelector((state: RootState) => state.todo);

    const addItemToList = () => {
        if (!title) return;

        dispatch(addItem(title));
    };

    const removeItemFromList = (item_id: number) => {
        dispatch(removeItem(item_id));
    };

    const toggleItemDone = (item_id: number) => {
        dispatch(markItemAsDone(item_id));
    };

    return (
        <div className="flex justify-center items-center h-screen">
            <div className="shadow-lg rounded-lg w-[500px]">
                <ListHeader
                    addItemToList={addItemToList}
                    title={title}
                    setTitle={setTitle}
                />
                <List
                    list={todo.todo_list}
                    removeItemFromList={removeItemFromList}
                    toggleItemDone={toggleItemDone}
                />
            </div>
        </div>
    );
}

export default App;

Again, we will update our List component interface to accept toggleItemDone function and call that function whenever checkbox value changes.

Would be also nice to cross the title of todo item when it is marked as done? Lets do that, it should be easy using Tailwind's predefined class line-through on the title of the item if todo item is marked as done.

import { Todo } from "../store/reducers/todo";

interface ListInterface {
    list: Todo[];
    removeItemFromList: Function;
    toggleItemDone: Function;
}

function List(props: ListInterface) {
    return (
        <ul className="p-8 pt-0 divide-y">
            {props.list.length > 0 && props.list.map((todo_item: Todo) => (
                <li key={todo_item.id} className="flex items-center p-2">
                    <input
                        onChange={() => props.toggleItemDone(todo_item.id)}
                        type="checkbox"
                        className="h-4 w-4 mr-2 text-indigo-600 focus:ring-indigo-500 border-gray-300 rounded"
                        checked={todo_item.is_done}
                    />
                    <p className={"w-full" + (todo_item.is_done ? ' line-through' : '')}>{todo_item.title}</p>
                    <button
                        onClick={() => props.removeItemFromList(todo_item.id)}
                        type="button"
                        className="w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-2 py-0.5 bg-white text-base font-medium text-gray-700 hover:bg-gray-100 focus:outline-none focus:ring-1 focus:ring-offset-2 focus:ring-red-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm"
                    >
                        Remove
                    </button>
                </li>
            ))}
            {props.list.length < 1 && (
                <p>Your todo list is empty, please add some todo.</p>
            )}
        </ul>
    );
}

export default List;

We should now be able to mark our items as done and it will mark these items as done in the Redux Store.