> For the complete documentation index, see [llms.txt](https://krzysztof-wierzbicki.gitbook.io/main/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://krzysztof-wierzbicki.gitbook.io/main/writing-samples/2022-2-front-end-react-composition-props-children/2022-4-front-end-react-task-component.md).

# React - Task component

The `Task` component will manage many things:

* displaying a single task,
* retrieving operations assigned to the task from the API,
* hiding and showing the form for adding operations,
* updating and deleting the task.

The following `props` set is given to the component:

* `title` - task title,
* `description` - task description,
* `id` - task ID,
* `status` - task status (open/closed), save it under the variable `_status` because of the local state with the same name,
* `onRemoveTask` - a method from the parent that allows us to remove the task from the local state of the `App`.

```js
function Task({title, description, id, status: _status, onRemoveTask}) {

}
```

Start by creating all the states needed for the component to work:

1. `status` - current status of our component. The initial value will be the status received through `props`.
2. `operations` - an array of operations for the specific task.
3. `operationForm` - value `true`/`false` indicating whether the form to add the task should be opened or closed.

```js
const [status, setStatus] = useState(_status);
const [operations, setOperations] = useState([]);
const [operationForm, setOperationForm] = useState(false);
```

## Tasks

This component must include methods that handle updating (`Finish`) and deleting a task. The `handleFinish` method must prepare the object with the task (exactly as the `NewTask` component earlier). In this case, `status` will have the value of `closed`.

We use here the `updateTask` API method, which we created earlier. We send it the `id` of our task, `task` object, and also the function that will be called when the API query has been called. This method will change the **local state** of the task to `closed`.

```js
/**
* Update task and set status to "finish"
*/
const handleFinish = () => {
  const task = {
    title,
    description,
    status: "closed"
  };

  /**
   * @function updateTask - API function
   */
  updateTask(id, task, () => {
    setStatus("closed");
  });
};
```

The function used for deleting tasks looks very similar. However, it calls another API method - `removeTask`. We pass it the `id` of the task, and the method that will be called when the task is actually removed from the database. In it, we use the method received from the parent - `onRemoveTask` and send the `id`. This will **remove** the task with the given ID **from the local state** of the `App` component and stop rendering it.

```js
/**
* Remove single task from DB and local state
*/
const handleRemove = () => {
  /**
   * @function removeTask - API function
   */
  removeTask(id, () => {
    /**
     * @function onRemoveTask - Function from parent component passed by props
     * Function is updating local state
     */
    onRemoveTask(id);
  });
};
```

## Operations

Next, let's create a function that will allow us to switch the `operationForm` state. We'll attach it to the `Add operation` button.

```js
/**
* Show/Hide add new operation form
*/
const toggleOperationForm = () => {
  setOperationForm(prevState => !prevState);
};
```

Of course, we have to retrieve all operations from the API server. We remember that such operations are performed after mounting the component, so here we will use the `useEffect` hook. We provide it with a function in which we call the `getOperations` API method with a task ID and a method that saves the retrieved data to the local state. We also pass an empty dependency array so that the data is retrieved only once during the component's lifecycle.

```js
useEffect(() => {
  /**
   * After component mount fetch all operation in this task
   * @function getOperations - API function
   */
  getOperations(id, setOperations);
}, []);
```

## JSX structure

Add `title` and `description`, and make the displaying of buttons conditional.

The "Add operation" and "Finish" buttons should be visible only if the task has `status: "open"`.

The button for deleting a task, on the other hand, can only appear if there are no more operations assigned to the task: `operations.length === 0` (the server will not allow the deletion of a task with existing operations).

Finally, attach the `Operations` component which we will discuss in the next article. It receives all retrieved operations (`props`), the state of the form (`open`/`closed`) together with the method, task ID and its status.

```js
return (
    <section className="card mt-5 shadow-sm">
      <div className="card-header d-flex justify-content-between align-items-center">
        <div>
          <h5>{title}</h5>
          <h6 className="card-subtitle text-muted">{description}</h6>
        </div>


        <div>
          {status === "open" && (
            <>
              <Button icon="fas fa-plus-circle"
                      color="info"
                      size="sm"
                      onClick={toggleOperationForm}
                      className="mr-2">
                Add operation
              </Button>

              <Button icon="fas fa-archive"
                      color="dark"
                      size="sm"
                      onClick={handleFinish}>
                Finish
              </Button>
            </>
          )}
          {operations.length === 0 &&
          <Button icon={"fas fa-trash"} color={"danger"} outline size={"sm"} onClick={handleRemove}
                  className="ml-2"/>}
        </div>
      </div>

      <Operations taskID={id}
                  form={operationForm}
                  setForm={setOperationForm}
                  operations={operations}
                  setOperations={setOperations}
                  status={status}/>
    </section>
);
```

```js
import React, {useState, useEffect} from "react";
import Operations from "./Operations";
import Button from "./Button";
import {removeTask, updateTask} from "../api/tasks";
import {getOperations} from "../api/operations";

function Task({title, description, id, status: _status, onRemoveTask}) {
  const [status, setStatus] = useState(_status);
  const [operations, setOperations] = useState([]);
  const [operationForm, setOperationForm] = useState(false);

  /**
   * Update task and set status to "finish"
   */
  const handleFinish = () => {
    const task = {
      title,
      description,
      status: "closed"
    };

    /**
     * @function updateTask - API function
     */
    updateTask(id, task, () => {
      setStatus("closed");
    });
  };

  /**
   * Remove single task from DB and local state
   */
  const handleRemove = () => {
    /**
     * @function removeTask - API function
     */
    removeTask(id, () => {
      /**
       * @function onRemoveTask - Function from parent component passed by props
       * Function is updating local state
       */
      onRemoveTask(id);
    });
  };


  /**
   * Show/Hide add new operation form
   */
  const toggleOperationForm = () => {
    setOperationForm(prevState => !prevState);
  };

  useEffect(() => {
    /**
     * After component mount fetch all operation in this task
     * @function getOperations - API function
     */
    getOperations(id, setOperations);
  }, []);


  return (
    <section className="card mt-5 shadow-sm">
      <div className="card-header d-flex justify-content-between align-items-center">
        <div>
          <h5>{title}</h5>
          <h6 className="card-subtitle text-muted">{description}</h6>
        </div>


        <div>
          {status === "open" && (
            <>
              <Button icon="fas fa-plus-circle"
                      color="info"
                      size="sm"
                      onClick={toggleOperationForm}
                      className="mr-2">
                Add operation
              </Button>

              <Button icon="fas fa-archive"
                      color="dark"
                      size="sm"
                      onClick={handleFinish}>
                Finish
              </Button>
            </>
          )}
          {operations.length === 0 &&
          <Button icon={"fas fa-trash"} color={"danger"} outline size={"sm"} onClick={handleRemove}
                  className="ml-2"/>}
        </div>
      </div>

      <Operations taskID={id}
                  form={operationForm}
                  setForm={setOperationForm}
                  operations={operations}
                  setOperations={setOperations}
                  status={status}/>
    </section>
  );
}

export default Task;
```
