diff --git a/js/components/header.js b/js/components/header.js index 68f50f7c..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; @@ -117,10 +129,6 @@ let Header = React.createClass({ ); }, - onChange(state) { - this.setState(state); - }, - onMenuItemClick() { /* This is a hack to make the dropdown close after clicking on an item @@ -156,16 +164,17 @@ let Header = React.createClass({ }, render() { + const { currentUser, unfilteredPieceListCount } = this.state; let account; let signup; let navRoutesLinks; - if (this.state.currentUser.username) { + if (currentUser.username) { account = ( + title={currentUser.username}> @@ -175,7 +184,7 @@ let Header = React.createClass({ ); + // 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 = ( + userAcl={currentUser.acl} /> ); } else { account = ( diff --git a/js/components/nav_routes_links.js b/js/components/nav_routes_links.js index 2a78a337..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 @@ -34,20 +53,29 @@ let NavRoutesLinks = React.createClass({ } const links = node.childRoutes.map((child, j) => { - const { aclName, headerTitle, path, childRoutes } = child; - let childrenFn = 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 childrenFn as false - if (child.childRoutes && child.childRoutes.length) { - childrenFn = this.extractLinksFromRoutes(child, userAcl, i++); - } + 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') { + 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') { @@ -56,21 +84,14 @@ let NavRoutesLinks = React.createClass({ key={j} aclName={aclName} aclObject={this.props.userAcl}> - + ); } else { return ( + {...navLinkProps} /> ); } } else { diff --git a/js/components/nav_routes_links_link.js b/js/components/nav_routes_links_link.js index eef98e59..6daec0ea 100644 --- a/js/components/nav_routes_links_link.js +++ b/js/components/nav_routes_links_link.js @@ -11,25 +11,26 @@ import LinkContainer from 'react-router-bootstrap/lib/LinkContainer'; let NavRoutesLinksLink = React.createClass({ propTypes: { - headerTitle: React.PropTypes.string, - routePath: React.PropTypes.string, - children: React.PropTypes.oneOfType([ React.PropTypes.arrayOf(React.PropTypes.element), React.PropTypes.element ]), - - depth: React.PropTypes.number + disabled: React.PropTypes.bool, + depth: React.PropTypes.number, + headerTitle: React.PropTypes.string, + routePath: React.PropTypes.string }, render() { - const { children, headerTitle, depth, routePath } = this.props; + const { children, headerTitle, depth, disabled, routePath } = this.props; // if the route has children, we're returning a DropdownButton that will get filled // with MenuItems if (children) { return ( - + {children} ); @@ -38,13 +39,17 @@ let NavRoutesLinksLink = React.createClass({ // if the node's child is actually a node of level one (a child of a node), we're // returning a DropdownButton matching MenuItem return ( - + {headerTitle} ); } else if (depth === 0) { return ( - + {headerTitle} ); diff --git a/js/components/whitelabel/prize/prize_routes.js b/js/components/whitelabel/prize/prize_routes.js index 5f80b30c..b8502004 100644 --- a/js/components/whitelabel/prize/prize_routes.js +++ b/js/components/whitelabel/prize/prize_routes.js @@ -54,7 +54,8 @@ const ROUTES = { + headerTitle='COLLECTION' + disableOn='noPieces' /> @@ -70,7 +71,8 @@ const ROUTES = { + headerTitle='SUBMISSIONS' + disableOn='noPieces' /> + headerTitle='COLLECTION' + disableOn='noPieces' /> @@ -109,7 +110,8 @@ let ROUTES = { + headerTitle='COLLECTION' + disableOn='noPieces' /> @@ -150,7 +152,8 @@ let ROUTES = { + headerTitle='COLLECTION' + disableOn='noPieces' /> @@ -189,7 +192,8 @@ let ROUTES = { + headerTitle='COLLECTION' + disableOn='noPieces' /> @@ -225,7 +229,8 @@ let ROUTES = { + headerTitle='COLLECTION' + disableOn='noPieces' /> diff --git a/js/routes.js b/js/routes.js index 49a284af..7a4fce2f 100644 --- a/js/routes.js +++ b/js/routes.js @@ -40,7 +40,8 @@ let COMMON_ROUTES = ( + headerTitle='COLLECTION' + disableOn='noPieces' />