0

I am working where I want to automatically collapse the menu when other one opens.Now I already tried making separate useState and passing values but it doesn't work.I am sharing the before and after code with you.

In Dashboard.jsx I am maping through the menus and passing it to MenuCards.jsx as props, now if A menu is clicked hence is Expandable, it is again passed to getExpandableMenu and the menu is exapanded. The end goal I want is one menu to open and if the other menu is clicked the first one to close first.

Before code -

// Dashboard.tsx

 setMenuList([
        {
          title: "Thermal Comfort",
          icon: thermal,
          decorator: new ManekinDecorator(IModelApp.viewManager.selectedView!),
          tooltip: "Thermal Comfort",
        },
        {
          title: "Surface Plots",
          icon: surfacePlot,
          decorator: null,
          tooltip: "Surface Plots",
        },
        {
          title: "Contour Plots",
          icon: contour,
          decorator: null,
          tooltip: "Contour Plots",
        },
        {
          title: "Comfort Cloud",
          icon: comfortCloud,
          decorator: new ComfortDecorator(),
          tooltip: "Comfort Cloud",
        },
        {
          title: "Flowlines",
          icon: flowline,
          //decorator: getFlowLineDecorator(),
          decorator: null,
          tooltip: "FlowLines",
        },
      ]);
    } else {
      setMenuList([]);
      setIsDropDownVisibal(false);
    }
  }, [viewPort]);

 <div className="menu">
            <div style={{ overflowY: "scroll", width: "inherit" }}>
              {menuList.map((menu) => (
                <MenuCard
                  menu={menu.title}
                  icon={menu.icon}
                  decorator={menu.decorator}
                  tooltip={menu.tooltip}
                />
              ))}
            </div>
          </div>

// MenuCard.tsx

const MenuCard = (props: any) => {
  const [toggle, setToggle] = React.useState(true);
  const [expandOption, setExpandOption] = React.useState(false);

  const onClick = () => {
    if (props.decorator !== null) {
      if (toggle) {
        IModelApp.viewManager.decorators.forEach((decorator) => {
          IModelApp.viewManager.dropDecorator(decorator);
        });

        IModelApp.viewManager.addDecorator(props.decorator);
      } else IModelApp.viewManager.dropDecorator(props.decorator);
    }
    setToggle(!toggle);
    setExpandOption(!expandOption);
  };
  const { menu, icon, tooltip } = props;
  return (
    <div>
      <div className="mainMenu" onClick={onClick}>
        <div className="icon">
          <img src={icon} alt="icon" className="menuIcon" />
        </div>
        <div className="menuTitle">
          <p className="title">{menu}</p>
        </div>
        <InfoTooltip tooltipText={tooltip} />
      </div>
      {expandOption && (
        <GetExpandedMenu menuName={menu} decorator={props.decorator} />
      )}
    </div>
  );
};

export default MenuCard;

// GetExpandedMenu.tsx

export default function GetExpandedMenu(props:any){
    const {menuName} = props
    const surfacePlotManager= new SurfacePlotManager()
    const contourPlotManager=new ContourPlotManager();

    switch(menuName) {
        case 'Surface Plots':
          return <SurfacePlot plotManager={surfacePlotManager}/>

        case 'Thermal Comfort':
          return <ThermalComfortMenu decorator={props.decorator}/>
        
        case 'Flowlines':
          return <FlowLines />

        case "Contour Plots":
          return <ContourPlot plotManager={contourPlotManager}/>;
            
        case 'Comfort Cloud':
          return <ComfortCloud/>
        default:
            return <p>expanded options</p>; 
      }
}

Here is what I tried doing which failed.

// MenuCard.tsx
// tried making separate useState for every menu

/* eslint-disable eqeqeq */
import React from "react";
import "./MenuCard.scss";

const MenuCard = (props: any) => {
  const [toggle, setToggle] = React.useState(true);
  const [expandOption, setExpandOption] = React.useState(false);
  const [ThermalExpandOption, setThermalExpandOption] = React.useState(false);
  const [SurfaceExpandOption, setSurfaceExpandOption] = React.useState(false);
  const [ContourExpandOption, setContourExpandOption] = React.useState(false);
  const [CloudExpandOption, setCloudExpandOption] = React.useState(false);
  const [FlowlinesExpandOption, setFlowlinesExpandOption] = React.useState(false);
  

  const onClick = () => {
    console.log("Menu clicked is", props.id);
    if (props.id == 0) {
      setThermalExpandOption(!ThermalExpandOption);
      setSurfaceExpandOption(false);
      setContourExpandOption(false);
      setCloudExpandOption(false);
      setFlowlinesExpandOption(false);
    } else if (props.id == 1) {
      setThermalExpandOption(false);
      setSurfaceExpandOption(!SurfaceExpandOption);
      setContourExpandOption(false);
      setCloudExpandOption(false);
      setFlowlinesExpandOption(false);
    } else if (props.id == 2) {
      setThermalExpandOption(false);
      setSurfaceExpandOption(false);
      setContourExpandOption(!CloudExpandOption);
      setCloudExpandOption(false);
      setFlowlinesExpandOption(false);
    } else if (props.id == 3) {
      setThermalExpandOption(false);
      setSurfaceExpandOption(false);
      setContourExpandOption(false);
      setCloudExpandOption(!CloudExpandOption);
      setFlowlinesExpandOption(false);
    } if (props.id == 4) {
      setThermalExpandOption(false);
      setSurfaceExpandOption(false);
      setContourExpandOption(false);
      setCloudExpandOption(false);
      setFlowlinesExpandOption(!FlowlinesExpandOption);
    } 
    if (props.decorator !== null) {
      if (toggle) {
        IModelApp.viewManager.decorators.forEach((decorator) => {
          IModelApp.viewManager.dropDecorator(decorator);
        });

        IModelApp.viewManager.addDecorator(props.decorator);
      } else IModelApp.viewManager.dropDecorator(props.decorator);
    }
    setToggle(!toggle);
    setExpandOption(!expandOption);
  };
  const { menu, icon, tooltip } = props;
  return (
    <div>
      <div className="mainMenu" onClick={onClick}>
        <div className="icon">
          <img src={icon} alt="icon" className="menuIcon" />
        </div>
        <div className="menuTitle">
          <p className="title">{menu}</p>
        </div>
        <InfoTooltip tooltipText={tooltip} />
      </div>
      { ThermalExpandOption  && (
        <GetExpandedMenu menuName={menu} decorator={props.decorator} />
      )}
      { SurfaceExpandOption  && (
        <GetExpandedMenu menuName={menu} decorator={props.decorator} />
      )}
      { ContourExpandOption  && (
        <GetExpandedMenu menuName={menu} decorator={props.decorator} />
      )}
      { CloudExpandOption  && (
        <GetExpandedMenu menuName={menu} decorator={props.decorator} />
      )}
      { FlowlinesExpandOption  && (
        <GetExpandedMenu menuName={menu} decorator={props.decorator} />
      )}
    </div>
  );
};

export default MenuCard;

1 Answers1

1

Lift state up.

If state of your item depends on state of menu item next to it, you can refactor both to depend on the state from "menu" container. Something like "openedItem" state.

You can find detailed instructions in React docs here: https://reactjs.org/docs/lifting-state-up.html , with examples.

Tymek
  • 3,000
  • 1
  • 25
  • 46