Source

DataModelArrayFieldTemplate.js

//React
import React, { useContext } from "react";

//Components
import FormDataStateContext from "./FormDataStateContext";

//Redux

//Styles
import { Accordion, Button } from "react-bootstrap";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import {
  faArrowUp,
  faPlus,
  faTrashAlt,
  faArrowDown,
} from "@fortawesome/free-solid-svg-icons";

//Other
import PropTypes from "prop-types";

/**
 * A data model ArrayFieldTemplate for react-jsonschema-form.
 *
 * @component
 */
const DataModelArrayFieldTemplate = (props) => {
  const [formData, setFormData] = useContext(FormDataStateContext);

  /**
   * Updates "formDate" on entity add.
   */
  const handleAddEntity = () => {
    setFormData([
      ...formData,
      {
        id: findHighestId(formData) + 1,
      },
    ]);
  };

  /**
   * Finds the highest among all objects inside an array of objects.
   *
   * @returns {number} Highest id found.
   */
  const findHighestId = (arr) => {
    let highest = 0;
    for (let i = 0; i < arr.length; i++) {
      if (arr[i].id > highest) {
        highest = arr[i].id;
      }
    }
    return highest;
  };

  /**
   * Transforms the title value from plural to singular.
   *
   * @param {string} types
   * @returns {string} Title in singular form.
   */
  const getTitle = (types) => {
    if (types === "Primitive properties") {
      return "Primitive property";
    } else if (types === "Reference properties") {
      return "Reference property";
    } else if (types === "Entities") {
      return "Entity";
    }
  };

  return (
    <>
      {formData && (
        <div className={props.className}>
          <Accordion>
            <p className="h4">{props.title}</p>
            {props.items &&
              props.items.map((element) => (
                <Accordion.Item className={element.className} key={element.key}>
                  <Accordion.Header>{getTitle(props.title)}</Accordion.Header>
                  <Accordion.Body>{element.children}</Accordion.Body>
                  {element.hasMoveDown && (
                    <Button
                      variant="outline-primary"
                      onClick={element.onReorderClick(
                        element.index,
                        element.index + 1
                      )}
                    >
                      <FontAwesomeIcon icon={faArrowDown} />
                    </Button>
                  )}

                  {element.hasMoveUp && (
                    <Button
                      variant="outline-primary"
                      onClick={element.onReorderClick(
                        element.index,
                        element.index - 1
                      )}
                    >
                      <FontAwesomeIcon icon={faArrowUp} />
                    </Button>
                  )}

                  <Button
                    variant="outline-primary"
                    onClick={element.onDropIndexClick(element.index)}
                  >
                    <FontAwesomeIcon icon={faTrashAlt} />
                  </Button>
                  <hr />
                </Accordion.Item>
              ))}

            {props.canAdd && (
              <Button
                variant="outline-primary"
                onClick={() => {
                  if (props.title === "Entities") {
                    handleAddEntity();
                  } else if (props.title === "Primitive properties") {
                    props.onAddClick();
                  } else if (props.title === "Reference properties") {
                    props.onAddClick();
                  }
                }}
              >
                <FontAwesomeIcon icon={faPlus} />
              </Button>
            )}
          </Accordion>
        </div>
      )}
    </>
  );
};

DataModelArrayFieldTemplate.propTypes = {
  /**
   * Props coming form "SchemaForm" component.
   */
  props: propTypes.object.isRequired,
};

export default DataModelArrayFieldTemplate;