diff --git a/js/components/header.js b/js/components/header.js index c16cba86..d2ecb76b 100644 --- a/js/components/header.js +++ b/js/components/header.js @@ -18,6 +18,8 @@ import AclProxy from './acl_proxy'; import EventActions from '../actions/event_actions'; +import PieceListStore from '../stores/piece_list_store'; + import UserActions from '../actions/user_actions'; import UserStore from '../stores/user_store'; @@ -43,12 +45,17 @@ let Header = React.createClass({ getInitialState() { return mergeOptions( + PieceListStore.getState(), WhitelabelStore.getState(), UserStore.getState() ); }, componentDidMount() { + // Listen to the piece list store, but don't fetch immediately to avoid + // conflicts with routes that may need to wait to load the piece list + PieceListStore.listen(this.onChange); + UserStore.listen(this.onChange); UserActions.fetchCurrentUser.defer(); @@ -75,11 +82,16 @@ let Header = React.createClass({ }, componentWillUnmount() { + PieceListStore.unlisten(this.onChange); UserStore.unlisten(this.onChange); WhitelabelStore.unlisten(this.onChange); //history.unlisten(this.onRouteChange); }, + onChange(state) { + this.setState(state); + }, + getLogo() { let { whitelabel } = this.state; @@ -93,16 +105,16 @@ let Header = React.createClass({ Whitelabel brand ); + } else { + return ( + + + + ); } - - return ( - - - - ); }, - getPoweredBy(){ + getPoweredBy() { return ( + title={currentUser.username}> @@ -174,7 +184,7 @@ let Header = React.createClass({ ); - navRoutesLinks = ; - } - else { + + // Let's assume that if the piece list hasn't loaded yet (ie. when unfilteredPieceListCount === -1) + // then the user has pieces + // FIXME: this doesn't work that well as the user may not load their piece list + // until much later, so we would show the 'Collection' header as available until + // they actually click on it and get redirected to piece registration. + navRoutesLinks = ( + + ); + } else { account = ( diff --git a/js/components/nav_routes_links.js b/js/components/nav_routes_links.js index b2c9d9c3..676a9896 100644 --- a/js/components/nav_routes_links.js +++ b/js/components/nav_routes_links.js @@ -11,14 +11,33 @@ import AclProxy from './acl_proxy'; import { sanitizeList } from '../utils/general_utils'; +const DISABLE_ENUM = ['hasPieces', 'noPieces']; + let NavRoutesLinks = React.createClass({ propTypes: { + hasPieces: React.PropTypes.bool, routes: React.PropTypes.arrayOf(React.PropTypes.object), userAcl: React.PropTypes.object }, + isRouteDisabled(disableOn) { + const { hasPieces } = this.props; + + if (disableOn) { + if (!DISABLE_ENUM.includes(disableOn)) { + throw new Error(`"disableOn" must be one of: [${DISABLE_ENUM.join(', ')}] got "${disableOn}" instead`); + } + + if (disableOn === 'hasPieces') { + return hasPieces; + } else if (disableOn === 'noPieces') { + return !hasPieces; + } + } + }, + /** - * This method generales a bunch of react-bootstrap specific links + * This method generates a bunch of react-bootstrap specific links * from the routes we defined in one of the specific routes.js file * * We can define a headerTitle as well as a aclName and according to that the @@ -29,48 +48,50 @@ let NavRoutesLinks = React.createClass({ * @return {Array} Array of ReactElements that can be displayed to the user */ extractLinksFromRoutes(node, userAcl, i) { - if(!node) { + if (!node) { return; } - let links = node.childRoutes.map((child, j) => { - let childrenFn = null; - let { aclName, headerTitle, path, childRoutes } = child; - - // If the node has children that could be rendered, then we want - // to execute this function again with the child as the root - // - // Otherwise we'll just pass childrenFn as false - if(child.childRoutes && child.childRoutes.length > 0) { - childrenFn = this.extractLinksFromRoutes(child, userAcl, i++); - } + const links = node.childRoutes.map((child, j) => { + const { aclName, disableOn, headerTitle, path, childRoutes } = child; // We validate if the user has set the title correctly, // otherwise we're not going to render his route - if(headerTitle && typeof headerTitle === 'string') { + if (headerTitle && typeof headerTitle === 'string') { + let nestedChildren = null; + + // If the node has children that could be rendered, then we want + // to execute this function again with the child as the root + // + // Otherwise we'll just pass nestedChildren as false + if (child.childRoutes && child.childRoutes.length) { + nestedChildren = this.extractLinksFromRoutes(child, userAcl, i++); + } + + const navLinkProps = { + headerTitle, + children: nestedChildren, + depth: i, + disabled: this.isRouteDisabled(disableOn), + routePath: `/${path}` + }; + // if there is an aclName present on the route definition, // we evaluate it against the user's acl - if(aclName && typeof aclName !== 'undefined') { + if (aclName && typeof aclName !== 'undefined') { return ( - + ); } else { return ( + {...navLinkProps} /> ); } } else { @@ -84,7 +105,7 @@ let NavRoutesLinks = React.createClass({ }, render() { - let {routes, userAcl} = this.props; + const {routes, userAcl} = this.props; return (