FarmBot/Farmbot-Web-App

View on GitHub
frontend/farm_designer/map/layers/plants/garden_plant.tsx

Summary

Maintainability
C
1 day
Test Coverage
import React from "react";
import { GardenPlantProps, GardenPlantState } from "../../interfaces";
import { svgToUrl } from "../../../../open_farm/icons";
import { transformXY, scaleIcon } from "../../util";
import { DragHelpers } from "../../active_plant/drag_helpers";
import { Color } from "../../../../ui";
import { Actions } from "../../../../constants";
import { cachedCrop } from "../../../../open_farm/cached_crop";
import { clickMapPlant } from "../../actions";
import { Circle } from "./circle";
import { SpecialStatus } from "farmbot";
import { FilePath } from "../../../../internal_urls";

export class GardenPlant extends
  React.Component<GardenPlantProps, Partial<GardenPlantState>> {

  state: GardenPlantState = { icon: FilePath.DEFAULT_ICON, hover: false };

  fetchIcon = () => {
    cachedCrop(this.props.plant.body.openfarm_slug)
      .then(({ svg_icon }) => {
        this.setState({ icon: svgToUrl(svg_icon) });
      });
  };

  componentDidMount = () => this.fetchIcon();
  componentDidUpdate = (prevProps: GardenPlantProps) =>
    this.props.plant.body.openfarm_slug != prevProps.plant.body.openfarm_slug &&
    this.fetchIcon();

  click = () => {
    this.props.dispatch(clickMapPlant(this.props.uuid, this.state.icon));
  };

  iconHover = (action: "start" | "end") => {
    const hovered = action === "start";
    this.props.dispatch({
      type: Actions.HOVER_PLANT_LIST_ITEM,
      payload: hovered ? this.props.uuid : undefined
    });
    this.setState({ hover: hovered });
  };

  get grayscale() {
    const { plant } = this.props;
    const unsaved = plant.specialStatus !== SpecialStatus.SAVED;
    const gridPlant = plant.kind == "Point" && plant.body.meta.gridId;
    const maybeGrayscale = (gridPlant && unsaved) ? "url(#grayscale)" : "";
    return maybeGrayscale;
  }

  // eslint-disable-next-line complexity
  render() {
    const {
      current, selected, dragging, plant, mapTransformProps,
      activeDragXY, zoomLvl, animate, editing, hovered, hoveredSpread,
    } = this.props;
    const { id, x, y } = plant.body;
    const { icon, hover } = this.state;
    const radius = (current || selected) && hoveredSpread
      ? hoveredSpread / 2
      : plant.body.radius;
    const plantIconSize = scaleIcon(radius);
    const iconRadius = hover ? plantIconSize * 1.1 : plantIconSize;
    const { qx, qy } = transformXY(x, y, mapTransformProps);
    const alpha = dragging ? 0.4 : 1.0;
    const newClass = id ? "" : "new";
    const className = [
      "plant-image",
      newClass,
      `is-chosen-${current || selected}`,
      animate ? "animate" : "",
    ].join(" ");

    return <g id={"plant-" + id}>
      <filter id="grayscale">
        <feColorMatrix type="saturate" values="0" />
      </filter>

      {animate &&
        <circle
          className={`soil-cloud ${newClass}`}
          cx={qx}
          cy={qy}
          r={plantIconSize}
          fill={Color.soilCloud}
          fillOpacity={0} />}

      {(current || selected) && !editing && !hovered &&
        <g id="selected-plant-indicator">
          <Circle
            className={`plant-indicator ${animate ? "animate" : ""}`}
            x={qx}
            y={qy}
            r={plantIconSize}
            selected={true} />
        </g>}

      <g id="plant-icon">
        <image
          onMouseEnter={() => this.iconHover("start")}
          onMouseLeave={() => this.iconHover("end")}
          visibility={dragging ? "hidden" : "visible"}
          className={className}
          opacity={alpha}
          filter={this.grayscale}
          xlinkHref={icon}
          onClick={this.click}
          height={iconRadius * 2}
          width={iconRadius * 2}
          x={qx - iconRadius}
          y={qy - iconRadius} />
      </g>

      <DragHelpers // for inactive plants
        dragging={dragging}
        plant={plant}
        mapTransformProps={mapTransformProps}
        zoomLvl={zoomLvl}
        activeDragXY={activeDragXY}
        plantAreaOffset={{ x: 0, y: 0 }} />
    </g>;
  }
}