refactor garden map legend

pull/973/head
gabrielburnworth 2018-08-27 12:29:01 -07:00
parent b3cf6c7261
commit 179de35a85
9 changed files with 182 additions and 155 deletions

View File

@ -10,69 +10,57 @@ jest.mock("../zoom", () => {
});
import * as React from "react";
import { shallow } from "enzyme";
import { GardenMapLegend } from "../garden_map_legend";
import { shallow, mount } from "enzyme";
import { GardenMapLegend, ZoomControls } from "../garden_map_legend";
import { GardenMapLegendProps } from "../interfaces";
import { clickButton } from "../../../__test_support__/helpers";
import { history } from "../../../history";
describe("<GardenMapLegend />", () => {
function fakeProps(): GardenMapLegendProps {
return {
zoom: () => () => undefined,
toggle: () => () => undefined,
updateBotOriginQuadrant: () => () => undefined,
botOriginQuadrant: 2,
legendMenuOpen: true,
showPlants: false,
showPoints: false,
showSpread: false,
showFarmbot: false,
showImages: false,
dispatch: jest.fn(),
tzOffset: 0,
getConfigValue: jest.fn(),
imageAgeInfo: { newestDate: "", toOldest: 1 },
};
}
const fakeProps = (): GardenMapLegendProps => ({
zoom: () => () => undefined,
toggle: () => () => undefined,
updateBotOriginQuadrant: () => () => undefined,
botOriginQuadrant: 2,
legendMenuOpen: true,
showPlants: false,
showPoints: false,
showSpread: false,
showFarmbot: false,
showImages: false,
dispatch: jest.fn(),
tzOffset: 0,
getConfigValue: jest.fn(),
imageAgeInfo: { newestDate: "", toOldest: 1 },
});
function checkZoomButtons(atMax: boolean, atMin: boolean, expected: number) {
mockAtMax = atMax;
mockAtMin = atMin;
const wrapper = shallow(<GardenMapLegend {...fakeProps()} />);
it("renders", () => {
const wrapper = mount(<GardenMapLegend {...fakeProps()} />);
["plants", "origin", "move"].map(string =>
expect(wrapper.text().toLowerCase()).toContain(string));
});
});
describe("<ZoomControls />", () => {
const expectDisabledBtnCountToEqual = (expected: number) => {
const wrapper = shallow(<ZoomControls
zoom={jest.fn()} />);
expect(wrapper.find(".disabled").length).toEqual(expected);
}
};
it("zoom buttons active", () => {
checkZoomButtons(false, false, 0);
mockAtMax = false;
mockAtMin = false;
expectDisabledBtnCountToEqual(0);
});
it("zoom out button disabled", () => {
checkZoomButtons(false, true, 1);
mockAtMax = false;
mockAtMin = true;
expectDisabledBtnCountToEqual(1);
});
it("zoom in button disabled", () => {
checkZoomButtons(true, false, 1);
});
it("enters 'move to' mode", () => {
const wrapper = shallow(<GardenMapLegend {...fakeProps()} />);
clickButton(wrapper, 2, "move mode");
expect(history.push).toHaveBeenCalledWith("/app/designer/plants/move_to");
});
it("opens saved garden panel", () => {
localStorage.setItem("SAVE_MY_GARDEN", "certainly");
const wrapper = shallow(<GardenMapLegend {...fakeProps()} />);
clickButton(wrapper, 3, "saved gardens");
expect(history.push).toHaveBeenCalledWith(
"/app/designer/plants/saved_gardens");
});
it("saved garden button hidden", () => {
localStorage.removeItem("SAVE_MY_GARDEN");
const wrapper = shallow(<GardenMapLegend {...fakeProps()} />);
const btn = wrapper.find("button").at(3);
expect(btn.props().hidden).toEqual(true);
mockAtMax = true;
mockAtMin = false;
expectDisabledBtnCountToEqual(1);
});
});

View File

@ -1,7 +1,7 @@
import * as React from "react";
import { shallow, mount } from "enzyme";
import {
Bugs, BugsProps, showBugResetButton, showBugs, resetBugs, bugsControls
Bugs, BugsProps, showBugResetButton, showBugs, resetBugs, BugsControls
} from "../bugs";
import { EggKeys, setEggStatus, getEggStatus } from "../status";
import { range } from "lodash";
@ -88,16 +88,16 @@ describe("resetBugs()", () => {
});
});
describe("bugsControls", () => {
describe("<BugsControls />", () => {
it("lays eggs", () => {
setEggStatus(EggKeys.BRING_ON_THE_BUGS, "");
const noEggs = shallow(bugsControls());
const noEggs = shallow(<BugsControls />);
expect(noEggs.find(".more-bugs").length).toEqual(0);
setEggStatus(EggKeys.BRING_ON_THE_BUGS, "true");
const stillNoEggs = shallow(bugsControls());
const stillNoEggs = shallow(<BugsControls />);
expect(stillNoEggs.find(".more-bugs").length).toEqual(0);
setEggStatus(EggKeys.BUGS_ARE_STILL_ALIVE, "false");
const eggs = shallow(bugsControls());
const eggs = shallow(<BugsControls />);
expect(eggs.find(".more-bugs").length).toEqual(1);
});
});

View File

@ -120,8 +120,8 @@ export class Bugs extends React.Component<BugsProps, BugsState> {
}
}
export const bugsControls = () => {
return showBugResetButton()
export const BugsControls = () =>
showBugResetButton()
? <div className="more-bugs">
<button
className="fb-button green"
@ -134,4 +134,3 @@ export const bugsControls = () => {
</p>}
</div>
: <div />;
};

View File

@ -5,114 +5,109 @@ import { GardenMapLegendProps } from "./interfaces";
import { history } from "../../history";
import { atMaxZoom, atMinZoom } from "./zoom";
import { ImageFilterMenu } from "./image_filter_menu";
import { bugsControls } from "./easter_eggs/bugs";
import { BugsControls } from "./easter_eggs/bugs";
import { BotOriginQuadrant } from "../interfaces";
import { MoveModeLink } from "../plants/move_to";
import { SavedGardensLink } from "../saved_gardens/saved_gardens";
export function GardenMapLegend(props: GardenMapLegendProps) {
const {
zoom,
toggle,
updateBotOriginQuadrant,
botOriginQuadrant,
legendMenuOpen,
showPlants,
showPoints,
showSpread,
showFarmbot,
showImages,
dispatch,
tzOffset,
getConfigValue,
imageAgeInfo,
} = props;
const OriginSelector = ({ quadrant, update }: {
quadrant: BotOriginQuadrant,
update: (quadrant: number) => () => void
}) =>
<div className="farmbot-origin">
<label>
{t("Origin")}
</label>
<div className="quadrants">
{[2, 1, 3, 4].map(q =>
<div key={"quadrant_" + q}
className={"quadrant " + (quadrant === q && "selected")}
onClick={update(q)} />
)}
</div>
</div>;
export const ZoomControls = ({ zoom }: { zoom: (value: number) => () => void }) => {
const plusBtnClass = atMaxZoom() ? "disabled" : "";
const minusBtnClass = atMinZoom() ? "disabled" : "";
const menuClass = legendMenuOpen ? "active" : "";
return <div className="zoom-buttons">
<button
className={"fb-button gray zoom " + plusBtnClass}
onClick={zoom(1)}>
<i className="fa fa-2x fa-plus" />
</button>
<button
className={"fb-button gray zoom zoom-out " + minusBtnClass}
onClick={zoom(-1)}>
<i className="fa fa-2x fa-minus" />
</button>
</div>;
};
const PointsSubMenu = () =>
<div>
<button className={"fb-button green"}
onClick={() => history.push("/app/designer/plants/create_point")}>
{t("Point Creator")}
</button>
</div>;
const LayerToggles = (props: GardenMapLegendProps) => {
const { toggle, getConfigValue } = props;
return <div className="toggle-buttons">
<LayerToggle
value={props.showPlants}
label={t("Plants?")}
onClick={toggle("show_plants")} />
<LayerToggle
value={props.showPoints}
label={t("Points?")}
onClick={toggle("show_points")}
popover={!!localStorage.getItem("FUTURE_FEATURES")
? <PointsSubMenu />
: undefined} />
<LayerToggle
value={props.showSpread}
label={t("Spread?")}
onClick={toggle("show_spread")} />
<LayerToggle
value={props.showFarmbot}
label={t("FarmBot?")}
onClick={toggle("show_farmbot")} />
<LayerToggle
value={props.showImages}
label={t("Photos?")}
onClick={toggle("show_images")}
popover={<ImageFilterMenu
tzOffset={props.tzOffset}
dispatch={props.dispatch}
getConfigValue={getConfigValue}
imageAgeInfo={props.imageAgeInfo} />} />
</div>;
};
export function GardenMapLegend(props: GardenMapLegendProps) {
const menuClass = props.legendMenuOpen ? "active" : "";
return <div
className={"garden-map-legend " + menuClass}
style={{ zoom: 1 }}>
<div
className={"menu-pullout " + menuClass}
onClick={toggle("legend_menu_open")}>
onClick={props.toggle("legend_menu_open")}>
<span>
{t("Menu")}
</span>
<i className="fa fa-2x fa-arrow-left" />
</div>
<div className="content">
<div className="zoom-buttons">
<button
className={"fb-button gray zoom " + plusBtnClass}
onClick={zoom(1)}>
<i className="fa fa-2x fa-plus" />
</button>
<button
className={"fb-button gray zoom zoom-out " + minusBtnClass}
onClick={zoom(-1)}>
<i className="fa fa-2x fa-minus" />
</button>
</div>
<div className="toggle-buttons">
<LayerToggle
value={showPlants}
label={t("Plants?")}
onClick={toggle("show_plants")} />
<LayerToggle
value={showPoints}
label={t("Points?")}
onClick={toggle("show_points")} />
<LayerToggle
value={showSpread}
label={t("Spread?")}
onClick={toggle("show_spread")} />
<LayerToggle
value={showFarmbot}
label={t("FarmBot?")}
onClick={toggle("show_farmbot")} />
<LayerToggle
value={showImages}
label={t("Photos?")}
onClick={toggle("show_images")}
popover={<ImageFilterMenu
tzOffset={tzOffset}
dispatch={dispatch}
getConfigValue={getConfigValue}
imageAgeInfo={imageAgeInfo} />} />
</div>
<div className="farmbot-origin">
<label>
{t("Origin")}
</label>
<div className="quadrants">
<div
className={"quadrant " + (botOriginQuadrant === 2 && "selected")}
onClick={updateBotOriginQuadrant(2)} />
<div
className={"quadrant " + (botOriginQuadrant === 1 && "selected")}
onClick={updateBotOriginQuadrant(1)} />
<div
className={"quadrant " + (botOriginQuadrant === 3 && "selected")}
onClick={updateBotOriginQuadrant(3)} />
<div
className={"quadrant " + (botOriginQuadrant === 4 && "selected")}
onClick={updateBotOriginQuadrant(4)} />
</div>
</div>
<div className="move-to-mode">
<button
className="fb-button gray"
onClick={() => history.push("/app/designer/plants/move_to")}>
{t("move mode")}
</button>
</div>
<button className="fb-button green"
hidden={!(localStorage.getItem("SAVE_MY_GARDEN") === "certainly")}
onClick={() => history.push("/app/designer/plants/saved_gardens")}>
{t("Saved Gardens")}
</button>
{bugsControls()}
<ZoomControls zoom={props.zoom} />
<LayerToggles {...props} />
<OriginSelector
quadrant={props.botOriginQuadrant}
update={props.updateBotOriginQuadrant} />
<MoveModeLink />
<SavedGardensLink />
<BugsControls />
</div>
</div>;
}

View File

@ -6,7 +6,7 @@ export interface LayerToggleProps {
label: string;
value: boolean | undefined;
onClick(): void;
popover?: JSX.Element;
popover?: JSX.Element | undefined;
}
/** A flipper type switch for showing/hiding the layers of the garden map. */

View File

@ -17,10 +17,13 @@ jest.mock("../../../history", () => ({
}));
import * as React from "react";
import { mount } from "enzyme";
import { MoveTo, MoveToProps, MoveToForm, MoveToFormProps } from "../move_to";
import { mount, shallow } from "enzyme";
import {
MoveTo, MoveToProps, MoveToForm, MoveToFormProps, MoveModeLink
} from "../move_to";
import { history } from "../../../history";
import { Actions } from "../../../constants";
import { clickButton } from "../../../__test_support__/helpers";
describe("<MoveTo />", () => {
beforeEach(function () {
@ -74,3 +77,11 @@ describe("<MoveToForm />", () => {
expect(mockDevice.moveAbsolute).toHaveBeenCalledWith({ x: 1, y: 2, z: 50 });
});
});
describe("<MoveModeLink />", () => {
it("enters 'move to' mode", () => {
const wrapper = shallow(<MoveModeLink />);
clickButton(wrapper, 0, "move mode");
expect(history.push).toHaveBeenCalledWith("/app/designer/plants/move_to");
});
});

View File

@ -125,3 +125,12 @@ export class MoveTo extends React.Component<MoveToProps, {}> {
</div>;
}
}
export const MoveModeLink = () =>
<div className="move-to-mode">
<button
className="fb-button gray"
onClick={() => history.push("/app/designer/plants/move_to")}>
{t("move mode")}
</button>
</div>;

View File

@ -20,7 +20,8 @@ import * as React from "react";
import { mount, shallow } from "enzyme";
import { snapshotGarden } from "../snapshot";
import {
SavedGardens, SavedGardensProps, GardenSnapshot, GardenSnapshotProps, mapStateToProps
SavedGardens, SavedGardensProps, GardenSnapshot, GardenSnapshotProps,
mapStateToProps, SavedGardensLink
} from "../saved_gardens";
import { error } from "farmbot-toastr";
import { clickButton } from "../../../__test_support__/helpers";
@ -127,3 +128,20 @@ describe("mapStateToProps()", () => {
expect(result.plantsInGarden).toEqual(true);
});
});
describe("<SavedGardensLink />", () => {
it("opens saved garden panel", () => {
localStorage.setItem("SAVE_MY_GARDEN", "certainly");
const wrapper = shallow(<SavedGardensLink />);
clickButton(wrapper, 0, "saved gardens");
expect(history.push).toHaveBeenCalledWith(
"/app/designer/plants/saved_gardens");
});
it("saved garden button hidden", () => {
localStorage.removeItem("SAVE_MY_GARDEN");
const wrapper = shallow(<SavedGardensLink />);
const btn = wrapper.find("button").at(0);
expect(btn.props().hidden).toEqual(true);
});
});

View File

@ -134,3 +134,10 @@ export class SavedGardens extends React.Component<SavedGardensProps, {}> {
</div>;
}
}
export const SavedGardensLink = () =>
<button className="fb-button green"
hidden={!(localStorage.getItem("FUTURE_FEATURES"))}
onClick={() => history.push("/app/designer/plants/saved_gardens")}>
{t("Saved Gardens")}
</button>;