import * as React from "react"; import { svgToUrl } from "../../open_farm/icons"; import { CropInfoProps, CropLiveSearchResult, OpenfarmSearch } from "../interfaces"; import { history, getPathArray } from "../../history"; import { connect } from "react-redux"; import { findBySlug } from "../search_selectors"; import { Everything } from "../../interfaces"; import { OpenFarm } from "../openfarm"; import { OFSearch } from "../util"; import { unselectPlant, setDragIcon } from "../actions"; import { validBotLocationData } from "../../util"; import { createPlant } from "../map/layers/plants/plant_actions"; import { round } from "../map/util"; import { BotPosition } from "../../devices/interfaces"; import { DesignerPanel, DesignerPanelHeader, DesignerPanelContent } from "./designer_panel"; import { Actions } from "../../constants"; import { EmptyStateWrapper, EmptyStateGraphic } from "../../ui/empty_state_wrapper"; import { startCase, isArray, chain, isNumber } from "lodash"; import { t } from "../../i18next_wrapper"; interface InfoFieldProps { title: string; children?: React.ReactNode; } interface SummaryItemProps { key: string; i: number; field: string; value: string; } /** Basic field: value display for OpenFarm crop properties. */ const InfoField = (props: InfoFieldProps) =>
  • {t(startCase(props.title))}

    {props.children}
  • ; const OMITTED_PROPERTIES = [ "slug", "processing_pictures", "description", "main_image_path", "tags_array", "guides_count" ]; const NO_VALUE = t("Not Set"); /** * If there's a value, give it an img element to render the * actual graphic. If no value, return NO_VALUE. */ const SvgIcon = ({ i, field, value }: SummaryItemProps) => {value ?
    : {NO_VALUE}}
    ; /** * Need to convert the `cm` provided by OpenFarm to `mm` * to match the Farm Designer units. */ const CmProperty = ({ i, field, value }: SummaryItemProps) => {!isNaN(parseInt(value)) ? (parseInt(value) * 10) + t("mm") : NO_VALUE} ; /** Comma-separated list of crop common names. */ const CommonNames = ({ i, field, value }: SummaryItemProps) => {(isArray(value) ? value.join(", ") : value) || NO_VALUE} ; /** Default behavior for all other properties. */ const DefaultPropertyDisplay = ({ i, field, value }: SummaryItemProps) => {value || NO_VALUE} ; /** Choose the appropriate display function for the crop property. */ const handleDisplay = ([field, value]: string[], i: number) => { const commonProps: SummaryItemProps = { key: field, i, field, value }; switch (field) { case "svg_icon": return ; case "spread": case "row_spacing": case "height": return ; case "common_names": return ; default: return ; } }; /** Display crop properties from OpenFarm. */ const CropInfoList = (crop: OpenFarm.OFCrop) => { return
      {chain(crop) .omit(OMITTED_PROPERTIES) .toPairs() .map(handleDisplay) .value()}
    ; }; /** Button to add a plant to the garden at the current bot position. */ const AddPlantHereButton = (props: { botPosition: BotPosition, openedSavedGarden: string | undefined, cropName: string, slug: string, dispatch: Function }) => { const { botPosition, openedSavedGarden, cropName, slug, dispatch } = props; const { x, y } = botPosition; const botXY = isNumber(x) && isNumber(y) ? { x: round(x), y: round(y) } : undefined; const botXYLabel = botXY ? `(${botXY.x}, ${botXY.y})` : "(unknown)"; const click = () => botXY ? createPlant({ cropName, slug, gardenCoords: botXY, gridSize: undefined, dispatch, openedSavedGarden }) : () => { }; return ; }; /** Image of crop to drag into map. */ const CropDragInfoTile = ({ image, svgIcon }: { image: string, svgIcon: string | undefined }) =>
    {t("Drag and drop into map")}
    ; /** Text and link for crop editing. */ const EditOnOpenFarm = ({ slug }: { slug: string }) =>
    {t("Edit on")}  {"OpenFarm"}
    ; /** Navigate to click-to-add panel. */ const AddToMapButton = ({ basePath, crop }: { basePath: string, crop: string }) => history.push(basePath + crop + "/add")}> {t("Add to map")} ; /** Get values common to crop panel headers. */ export const getCropHeaderProps = (props: { cropSearchResults: CropLiveSearchResult[] }) => { const crop = getPathArray()[5]; const result = findBySlug(props.cropSearchResults, crop || ""); const basePath = "/app/designer/plants/crop_search/"; const backgroundURL = `linear-gradient( rgba(0, 0, 0, 0.7), rgba(0, 0, 0, 0.7)), url(${result.image})`; return { crop, result, basePath, backgroundURL }; }; export function mapStateToProps(props: Everything): CropInfoProps { const { cropSearchResults, openedSavedGarden, cropSearchInProgress, cropSearchQuery } = props.resources.consumers.farm_designer; return { openfarmSearch: OFSearch, dispatch: props.dispatch, cropSearchQuery, cropSearchResults, cropSearchInProgress, openedSavedGarden, botPosition: validBotLocationData(props.bot.hardware.location_data).position }; } /** Get OpenFarm crop search results for crop info page contents. */ export const searchForCurrentCrop = (openfarmSearch: OpenfarmSearch) => (dispatch: Function) => { const crop = getPathArray()[5]; openfarmSearch(crop)(dispatch); unselectPlant(dispatch)(); }; export class RawCropInfo extends React.Component { componentDidMount() { this.props.dispatch(searchForCurrentCrop(this.props.openfarmSearch)); } /** Clear the current crop search results. */ clearCropSearchResults = (crop: string) => () => { const { dispatch } = this.props; if (!this.props.cropSearchQuery) { dispatch({ type: Actions.SEARCH_QUERY_CHANGE, payload: crop }); } dispatch({ type: Actions.OF_SEARCH_RESULTS_OK, payload: [] }); }; render() { const { cropSearchResults, cropSearchInProgress } = this.props; const { crop, result, basePath, backgroundURL } = getCropHeaderProps({ cropSearchResults }); const panelName = "crop-info"; return ; } } export const CropInfo = connect(mapStateToProps)(RawCropInfo);