github.com/replicatedhq/ship@v0.55.0/web/init/src/components/shared/NavBar.jsx (about)

     1  import React, { Fragment } from "react";
     2  import assign from "object-assign";
     3  import { Link, withRouter } from "react-router-dom";
     4  import StepNumbers from "./StepNumbers";
     5  import upperFirst from "lodash/upperFirst";
     6  import NavItem from "./NavItem";
     7  // This is hardcoded for now as we're bundling it from `@replicatedhq/ship-init`
     8  // and then re-bundling the svg as a part of the `@replicatedhq/ship-app` bundle
     9  // for it to be served via the ship binary. As part of the bundling process the name
    10  // is mutated to a data-uri twice.
    11  // Do not remove the import.
    12  import "../../assets/images/ship-logo.png";
    13  const shipLogo = "static/media/b3d517c0409239a363a3c18ce9a0eda2.b3d517c0.png";
    14  export class NavBar extends React.Component {
    15  
    16    constructor() {
    17      super();
    18      this.state = {
    19        navDetails: {
    20          name: "",
    21          icon: "",
    22        },
    23        imageLoaded: false,
    24      };
    25    }
    26  
    27    isActive = (pathname = "") => {
    28      return (item = {}) => {
    29        if (!item.linkTo) return false;
    30        return pathname.indexOf(`${item.linkTo}`) > -1;
    31      };
    32    }
    33  
    34    handleRouteChange = (route, dropdownKey) => {
    35      if (this.state[`${dropdownKey}Active`]) {
    36        this.setState({
    37          [`${dropdownKey}Active`]: false
    38        });
    39      }
    40      const { basePath } = this.props;
    41      this.props.history.push(`${basePath}/${route}`);
    42    }
    43  
    44    handleLogOut = (e) => {
    45      e.preventDefault();
    46    }
    47  
    48    getNavItems = () => {
    49      const token = true;
    50      return[ !token ? null :
    51        {
    52          id: 0,
    53          label: "Dashboard",
    54          linkTo: "/dashboard",
    55          isActive: this.props.location.pathname === "/dashboard",
    56          position: "left",
    57        },
    58      {
    59        id: 1,
    60        label: "Audit log",
    61        linkTo: "/audit-log",
    62        isActive: this.props.location.pathname === "/audit-log",
    63        position: "left",
    64      },
    65      !token ? null : {
    66        id: 2,
    67        label: "Logout",
    68        onClick: (e) => { this.handleLogOut(e) },
    69        position: "right"
    70      }
    71      ];
    72    }
    73  
    74    combineItems = (methods) => {
    75      return methods.reduce((accum, method) => (
    76        accum.concat(method(this.props))
    77      ), []);
    78    }
    79  
    80    onClick = (item) => {
    81      return (e, ...rest) => {
    82        const activeKey = `${item.dropdownLabel || item.id || ""}Active`;
    83        if (item.href) return;
    84        if (typeof item.onClick === "function") {
    85          item.onClick(e, ...rest);
    86          return;
    87        }
    88        this.setState({
    89          [activeKey]: !this.state[activeKey]
    90        });
    91      };
    92    }
    93  
    94    preloadNavIconImage = (iconUrl) => new Promise(
    95      (resolve, reject) => {
    96        var image = new Image();
    97        image.onload = resolve;
    98        image.onerror = reject;
    99        image.src = iconUrl;
   100      }
   101    )
   102  
   103    componentDidUpdate() {
   104      const { shipAppMetadata } = this.props;
   105      const { imageLoaded } = this.state;
   106  
   107      if (!imageLoaded && shipAppMetadata.loaded) {
   108        this.preloadNavIconImage(shipAppMetadata.icon)
   109          .then(() => {
   110            this.setState({
   111              navDetails: {
   112                name: shipAppMetadata.name,
   113                icon: shipAppMetadata.icon,
   114              },
   115              imageLoaded: true,
   116            })
   117          })
   118          .catch(() => this.setState({
   119            navDetails: {
   120              name: shipAppMetadata.name,
   121              icon: shipLogo,
   122            },
   123            imageLoaded: true,
   124          }));
   125      }
   126    }
   127  
   128    render() {
   129      const { className, routes, basePath } = this.props;
   130      const { navDetails, imageLoaded } = this.state;
   131      const isPathActive = this.isActive(
   132        typeof window === "object"
   133          ? window.location.pathname
   134          : "",
   135      );
   136  
   137      const itemsArr = [this.getNavItems.bind(this)];
   138      // build items
   139      const headerItems = this.combineItems(itemsArr)
   140        .filter(item => item)
   141        .map(item => (assign(item, {
   142          isActive: isPathActive(item),
   143        })));
   144      const renderItem = item => {
   145        return (
   146          <NavItem
   147            key={item.id}
   148            {...item}
   149            onClick={this.onClick(item)}
   150            isDropDownActive={this.state[`${item.dropdownLabel || item.id || ""}Active`]}
   151          />
   152        );
   153      };
   154  
   155      const rightItems = headerItems.filter(item => item.position === "right");
   156      const leftItems = headerItems.filter(item => item.position === "left");
   157  
   158      const [ firstRoute = {} ] = routes;
   159      const { id: firstRouteId } = firstRoute;
   160  
   161      const headerLogo = (
   162        <div className="HeaderLogo-wrapper flex-column flex1 flex-verticalCenter u-position--relative">
   163          <div className="HeaderLogo">
   164            <Link to={`/${firstRouteId}`} tabIndex="-1">
   165              <img src={navDetails.icon} className="logo" />
   166            </Link>
   167          </div>
   168        </div>
   169      );
   170  
   171      const headerName = navDetails && navDetails.icon ? null : (
   172        <div className="flex-column flex-auto HeaderName-wrapper">
   173          {navDetails.name && navDetails.name.length ?
   174            <div className="flex-column flex1 flex-verticalCenter u-position--relative">
   175              <p className="u-fontSize--larger u-fontWeight--bold u-color--tundora u-lineHeight--default u-marginRight--30">{upperFirst(navDetails.name)}</p>
   176            </div>
   177            : <div className="flex-column flex1 flex-verticalCenter u-position--relative">
   178              <p className="u-fontSize--larger u-fontWeight--bold u-color--tundora u-lineHeight--default u-marginRight--30">Replicated Ship</p>
   179            </div>
   180          }
   181        </div>
   182      );
   183  
   184      return (
   185        <div className={`NavBarWrapper flex flex-auto ${className || ""}`}>
   186          <div className="container flex flex1">
   187            <div className="flex1 flex justifyContent--center alignItems--center">
   188              <div className="flex1 flex">
   189                <div className="flex flex-auto metadata-wrapper">
   190                  {
   191                    imageLoaded ?
   192                      (
   193                        <Fragment>
   194                          {headerLogo}
   195                          {headerName}
   196                        </Fragment>
   197                      ) :
   198                      null
   199                  }
   200                  {this.props.hideLinks ? null :
   201                    <div className="flex flex-auto alignItems--center left-items">
   202                      {leftItems.map(renderItem)}
   203                    </div>
   204                  }
   205                </div>
   206                {this.props.hideSteps ? null :
   207                  <div className="flex flex1">
   208                    <StepNumbers basePath={basePath} steps={routes} inNav={true} />
   209                  </div>
   210                }
   211                {this.props.hideLinks ? null :
   212                  <div className="flex flex1 justifyContent--flexEnd right-items">
   213                    <div className="flex flex-auto alignItems--center">
   214                      {rightItems.map(renderItem)}
   215                    </div>
   216                  </div>
   217                }
   218              </div>
   219            </div>
   220          </div>
   221        </div>
   222      );
   223    }
   224  }
   225  
   226  
   227  export default withRouter(NavBar);