mirror of
https://github.com/ascribe/onion.git
synced 2024-12-22 17:33:14 +01:00
Disable 'Collection' header item when no pieces are found for the user
The disabling only happens when the piece list is fetched, which may not happen immediately in some cases (ie. logged in user goes straight to another person’s edition first). We’re not able to fetch the piece list immediately, as some white labels apply default filters on the piece list which forces them to wait until they can begin fetching their piece lists.
This commit is contained in:
parent
9b1e6cc8a1
commit
9559bc09b4
@ -18,6 +18,8 @@ import AclProxy from './acl_proxy';
|
|||||||
|
|
||||||
import EventActions from '../actions/event_actions';
|
import EventActions from '../actions/event_actions';
|
||||||
|
|
||||||
|
import PieceListStore from '../stores/piece_list_store';
|
||||||
|
|
||||||
import UserActions from '../actions/user_actions';
|
import UserActions from '../actions/user_actions';
|
||||||
import UserStore from '../stores/user_store';
|
import UserStore from '../stores/user_store';
|
||||||
|
|
||||||
@ -43,12 +45,17 @@ let Header = React.createClass({
|
|||||||
|
|
||||||
getInitialState() {
|
getInitialState() {
|
||||||
return mergeOptions(
|
return mergeOptions(
|
||||||
|
PieceListStore.getState(),
|
||||||
WhitelabelStore.getState(),
|
WhitelabelStore.getState(),
|
||||||
UserStore.getState()
|
UserStore.getState()
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
componentDidMount() {
|
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);
|
UserStore.listen(this.onChange);
|
||||||
UserActions.fetchCurrentUser.defer();
|
UserActions.fetchCurrentUser.defer();
|
||||||
|
|
||||||
@ -75,11 +82,16 @@ let Header = React.createClass({
|
|||||||
},
|
},
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
|
PieceListStore.unlisten(this.onChange);
|
||||||
UserStore.unlisten(this.onChange);
|
UserStore.unlisten(this.onChange);
|
||||||
WhitelabelStore.unlisten(this.onChange);
|
WhitelabelStore.unlisten(this.onChange);
|
||||||
//history.unlisten(this.onRouteChange);
|
//history.unlisten(this.onRouteChange);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onChange(state) {
|
||||||
|
this.setState(state);
|
||||||
|
},
|
||||||
|
|
||||||
getLogo() {
|
getLogo() {
|
||||||
let { whitelabel } = this.state;
|
let { whitelabel } = this.state;
|
||||||
|
|
||||||
@ -117,10 +129,6 @@ let Header = React.createClass({
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
onChange(state) {
|
|
||||||
this.setState(state);
|
|
||||||
},
|
|
||||||
|
|
||||||
onMenuItemClick() {
|
onMenuItemClick() {
|
||||||
/*
|
/*
|
||||||
This is a hack to make the dropdown close after clicking on an item
|
This is a hack to make the dropdown close after clicking on an item
|
||||||
@ -156,16 +164,17 @@ let Header = React.createClass({
|
|||||||
},
|
},
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
const { currentUser, unfilteredPieceListCount } = this.state;
|
||||||
let account;
|
let account;
|
||||||
let signup;
|
let signup;
|
||||||
let navRoutesLinks;
|
let navRoutesLinks;
|
||||||
|
|
||||||
if (this.state.currentUser.username) {
|
if (currentUser.username) {
|
||||||
account = (
|
account = (
|
||||||
<DropdownButton
|
<DropdownButton
|
||||||
ref='dropdownbutton'
|
ref='dropdownbutton'
|
||||||
eventKey="1"
|
eventKey="1"
|
||||||
title={this.state.currentUser.username}>
|
title={currentUser.username}>
|
||||||
<LinkContainer
|
<LinkContainer
|
||||||
to="/settings"
|
to="/settings"
|
||||||
onClick={this.onMenuItemClick}>
|
onClick={this.onMenuItemClick}>
|
||||||
@ -175,7 +184,7 @@ let Header = React.createClass({
|
|||||||
</MenuItem>
|
</MenuItem>
|
||||||
</LinkContainer>
|
</LinkContainer>
|
||||||
<AclProxy
|
<AclProxy
|
||||||
aclObject={this.state.currentUser.acl}
|
aclObject={currentUser.acl}
|
||||||
aclName="acl_view_settings_contract">
|
aclName="acl_view_settings_contract">
|
||||||
<LinkContainer
|
<LinkContainer
|
||||||
to="/contract_settings"
|
to="/contract_settings"
|
||||||
@ -197,12 +206,18 @@ let Header = React.createClass({
|
|||||||
</DropdownButton>
|
</DropdownButton>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// 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 = (
|
navRoutesLinks = (
|
||||||
<NavRoutesLinks
|
<NavRoutesLinks
|
||||||
navbar
|
navbar
|
||||||
right
|
right
|
||||||
|
hasPieces={!!unfilteredPieceListCount}
|
||||||
routes={this.props.routes}
|
routes={this.props.routes}
|
||||||
userAcl={this.state.currentUser.acl} />
|
userAcl={currentUser.acl} />
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
account = (
|
account = (
|
||||||
|
@ -11,14 +11,33 @@ import AclProxy from './acl_proxy';
|
|||||||
import { sanitizeList } from '../utils/general_utils';
|
import { sanitizeList } from '../utils/general_utils';
|
||||||
|
|
||||||
|
|
||||||
|
const DISABLE_ENUM = ['hasPieces', 'noPieces'];
|
||||||
|
|
||||||
let NavRoutesLinks = React.createClass({
|
let NavRoutesLinks = React.createClass({
|
||||||
propTypes: {
|
propTypes: {
|
||||||
|
hasPieces: React.PropTypes.bool,
|
||||||
routes: React.PropTypes.arrayOf(React.PropTypes.object),
|
routes: React.PropTypes.arrayOf(React.PropTypes.object),
|
||||||
userAcl: 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
|
* 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
|
* 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 links = node.childRoutes.map((child, j) => {
|
||||||
const { aclName, headerTitle, path, childRoutes } = child;
|
const { aclName, disableOn, 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++);
|
|
||||||
}
|
|
||||||
|
|
||||||
// We validate if the user has set the title correctly,
|
// We validate if the user has set the title correctly,
|
||||||
// otherwise we're not going to render his route
|
// 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,
|
// if there is an aclName present on the route definition,
|
||||||
// we evaluate it against the user's acl
|
// we evaluate it against the user's acl
|
||||||
if (aclName && typeof aclName !== 'undefined') {
|
if (aclName && typeof aclName !== 'undefined') {
|
||||||
@ -56,21 +84,14 @@ let NavRoutesLinks = React.createClass({
|
|||||||
key={j}
|
key={j}
|
||||||
aclName={aclName}
|
aclName={aclName}
|
||||||
aclObject={this.props.userAcl}>
|
aclObject={this.props.userAcl}>
|
||||||
<NavRoutesLinksLink
|
<NavRoutesLinksLink {...navLinkProps} />
|
||||||
headerTitle={headerTitle}
|
|
||||||
routePath={'/' + path}
|
|
||||||
depth={i}
|
|
||||||
children={childrenFn} />
|
|
||||||
</AclProxy>
|
</AclProxy>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<NavRoutesLinksLink
|
<NavRoutesLinksLink
|
||||||
key={j}
|
key={j}
|
||||||
headerTitle={headerTitle}
|
{...navLinkProps} />
|
||||||
routePath={'/' + path}
|
|
||||||
depth={i}
|
|
||||||
children={childrenFn} />
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -11,25 +11,26 @@ import LinkContainer from 'react-router-bootstrap/lib/LinkContainer';
|
|||||||
|
|
||||||
let NavRoutesLinksLink = React.createClass({
|
let NavRoutesLinksLink = React.createClass({
|
||||||
propTypes: {
|
propTypes: {
|
||||||
headerTitle: React.PropTypes.string,
|
|
||||||
routePath: React.PropTypes.string,
|
|
||||||
|
|
||||||
children: React.PropTypes.oneOfType([
|
children: React.PropTypes.oneOfType([
|
||||||
React.PropTypes.arrayOf(React.PropTypes.element),
|
React.PropTypes.arrayOf(React.PropTypes.element),
|
||||||
React.PropTypes.element
|
React.PropTypes.element
|
||||||
]),
|
]),
|
||||||
|
disabled: React.PropTypes.bool,
|
||||||
depth: React.PropTypes.number
|
depth: React.PropTypes.number,
|
||||||
|
headerTitle: React.PropTypes.string,
|
||||||
|
routePath: React.PropTypes.string
|
||||||
},
|
},
|
||||||
|
|
||||||
render() {
|
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
|
// if the route has children, we're returning a DropdownButton that will get filled
|
||||||
// with MenuItems
|
// with MenuItems
|
||||||
if (children) {
|
if (children) {
|
||||||
return (
|
return (
|
||||||
<DropdownButton title={headerTitle}>
|
<DropdownButton
|
||||||
|
disabled={disabled}
|
||||||
|
title={headerTitle}>
|
||||||
{children}
|
{children}
|
||||||
</DropdownButton>
|
</DropdownButton>
|
||||||
);
|
);
|
||||||
@ -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
|
// if the node's child is actually a node of level one (a child of a node), we're
|
||||||
// returning a DropdownButton matching MenuItem
|
// returning a DropdownButton matching MenuItem
|
||||||
return (
|
return (
|
||||||
<LinkContainer to={routePath}>
|
<LinkContainer
|
||||||
|
disabled={disabled}
|
||||||
|
to={routePath}>
|
||||||
<MenuItem>{headerTitle}</MenuItem>
|
<MenuItem>{headerTitle}</MenuItem>
|
||||||
</LinkContainer>
|
</LinkContainer>
|
||||||
);
|
);
|
||||||
} else if (depth === 0) {
|
} else if (depth === 0) {
|
||||||
return (
|
return (
|
||||||
<LinkContainer to={routePath}>
|
<LinkContainer
|
||||||
|
disabled={disabled}
|
||||||
|
to={routePath}>
|
||||||
<NavItem>{headerTitle}</NavItem>
|
<NavItem>{headerTitle}</NavItem>
|
||||||
</LinkContainer>
|
</LinkContainer>
|
||||||
);
|
);
|
||||||
|
@ -54,7 +54,8 @@ const ROUTES = {
|
|||||||
<Route
|
<Route
|
||||||
path='collection'
|
path='collection'
|
||||||
component={ProxyHandler(AuthRedirect({to: '/login', when: 'loggedOut'}))(SPPieceList)}
|
component={ProxyHandler(AuthRedirect({to: '/login', when: 'loggedOut'}))(SPPieceList)}
|
||||||
headerTitle='COLLECTION'/>
|
headerTitle='COLLECTION'
|
||||||
|
disableOn='noPieces' />
|
||||||
<Route path='pieces/:pieceId' component={SluicePieceContainer} />
|
<Route path='pieces/:pieceId' component={SluicePieceContainer} />
|
||||||
<Route path='editions/:editionId' component={EditionContainer} />
|
<Route path='editions/:editionId' component={EditionContainer} />
|
||||||
<Route path='verify' component={CoaVerifyContainer} />
|
<Route path='verify' component={CoaVerifyContainer} />
|
||||||
@ -70,7 +71,8 @@ const ROUTES = {
|
|||||||
<Route
|
<Route
|
||||||
path='collection'
|
path='collection'
|
||||||
component={ProxyHandler(AuthRedirect({to: '/login', when: 'loggedOut'}))(SPPieceList)}
|
component={ProxyHandler(AuthRedirect({to: '/login', when: 'loggedOut'}))(SPPieceList)}
|
||||||
headerTitle='SUBMISSIONS'/>
|
headerTitle='SUBMISSIONS'
|
||||||
|
disableOn='noPieces' />
|
||||||
<Route
|
<Route
|
||||||
path='login'
|
path='login'
|
||||||
component={ProxyHandler(
|
component={ProxyHandler(
|
||||||
|
@ -75,7 +75,8 @@ let ROUTES = {
|
|||||||
<Route
|
<Route
|
||||||
path='collection'
|
path='collection'
|
||||||
component={ProxyHandler(AuthRedirect({to: '/login', when: 'loggedOut'}))(CylandPieceList)}
|
component={ProxyHandler(AuthRedirect({to: '/login', when: 'loggedOut'}))(CylandPieceList)}
|
||||||
headerTitle='COLLECTION' />
|
headerTitle='COLLECTION'
|
||||||
|
disableOn='noPieces' />
|
||||||
<Route path='editions/:editionId' component={EditionContainer} />
|
<Route path='editions/:editionId' component={EditionContainer} />
|
||||||
<Route path='verify' component={CoaVerifyContainer} />
|
<Route path='verify' component={CoaVerifyContainer} />
|
||||||
<Route path='pieces/:pieceId' component={CylandPieceContainer} />
|
<Route path='pieces/:pieceId' component={CylandPieceContainer} />
|
||||||
@ -109,7 +110,8 @@ let ROUTES = {
|
|||||||
<Route
|
<Route
|
||||||
path='collection'
|
path='collection'
|
||||||
component={ProxyHandler(AuthRedirect({to: '/login', when: 'loggedOut'}))(PieceList)}
|
component={ProxyHandler(AuthRedirect({to: '/login', when: 'loggedOut'}))(PieceList)}
|
||||||
headerTitle='COLLECTION' />
|
headerTitle='COLLECTION'
|
||||||
|
disableOn='noPieces' />
|
||||||
<Route path='pieces/:pieceId' component={PieceContainer} />
|
<Route path='pieces/:pieceId' component={PieceContainer} />
|
||||||
<Route path='editions/:editionId' component={EditionContainer} />
|
<Route path='editions/:editionId' component={EditionContainer} />
|
||||||
<Route path='verify' component={CoaVerifyContainer} />
|
<Route path='verify' component={CoaVerifyContainer} />
|
||||||
@ -150,7 +152,8 @@ let ROUTES = {
|
|||||||
<Route
|
<Route
|
||||||
path='collection'
|
path='collection'
|
||||||
component={ProxyHandler(AuthRedirect({to: '/login', when: 'loggedOut'}))(IkonotvPieceList)}
|
component={ProxyHandler(AuthRedirect({to: '/login', when: 'loggedOut'}))(IkonotvPieceList)}
|
||||||
headerTitle='COLLECTION' />
|
headerTitle='COLLECTION'
|
||||||
|
disableOn='noPieces' />
|
||||||
<Route
|
<Route
|
||||||
path='contract_notifications'
|
path='contract_notifications'
|
||||||
component={ProxyHandler(AuthRedirect({to: '/login', when: 'loggedOut'}))(IkonotvContractNotifications)} />
|
component={ProxyHandler(AuthRedirect({to: '/login', when: 'loggedOut'}))(IkonotvContractNotifications)} />
|
||||||
@ -189,7 +192,8 @@ let ROUTES = {
|
|||||||
<Route
|
<Route
|
||||||
path='collection'
|
path='collection'
|
||||||
component={ProxyHandler(AuthRedirect({to: '/login', when: 'loggedOut'}))(MarketPieceList)}
|
component={ProxyHandler(AuthRedirect({to: '/login', when: 'loggedOut'}))(MarketPieceList)}
|
||||||
headerTitle='COLLECTION' />
|
headerTitle='COLLECTION'
|
||||||
|
disableOn='noPieces' />
|
||||||
<Route path='pieces/:pieceId' component={MarketPieceContainer} />
|
<Route path='pieces/:pieceId' component={MarketPieceContainer} />
|
||||||
<Route path='editions/:editionId' component={MarketEditionContainer} />
|
<Route path='editions/:editionId' component={MarketEditionContainer} />
|
||||||
<Route path='verify' component={CoaVerifyContainer} />
|
<Route path='verify' component={CoaVerifyContainer} />
|
||||||
@ -225,7 +229,8 @@ let ROUTES = {
|
|||||||
<Route
|
<Route
|
||||||
path='collection'
|
path='collection'
|
||||||
component={ProxyHandler(AuthRedirect({to: '/login', when: 'loggedOut'}))(Vivi23PieceList)}
|
component={ProxyHandler(AuthRedirect({to: '/login', when: 'loggedOut'}))(Vivi23PieceList)}
|
||||||
headerTitle='COLLECTION' />
|
headerTitle='COLLECTION'
|
||||||
|
disableOn='noPieces' />
|
||||||
<Route path='pieces/:pieceId' component={MarketPieceContainer} />
|
<Route path='pieces/:pieceId' component={MarketPieceContainer} />
|
||||||
<Route path='editions/:editionId' component={MarketEditionContainer} />
|
<Route path='editions/:editionId' component={MarketEditionContainer} />
|
||||||
<Route path='verify' component={CoaVerifyContainer} />
|
<Route path='verify' component={CoaVerifyContainer} />
|
||||||
|
@ -40,7 +40,8 @@ let COMMON_ROUTES = (
|
|||||||
<Route
|
<Route
|
||||||
path='collection'
|
path='collection'
|
||||||
component={ProxyHandler(AuthRedirect({to: '/login', when: 'loggedOut'}))(PieceList)}
|
component={ProxyHandler(AuthRedirect({to: '/login', when: 'loggedOut'}))(PieceList)}
|
||||||
headerTitle='COLLECTION'/>
|
headerTitle='COLLECTION'
|
||||||
|
disableOn='noPieces' />
|
||||||
<Route
|
<Route
|
||||||
path='signup'
|
path='signup'
|
||||||
component={ProxyHandler(AuthRedirect({to: '/collection', when: 'loggedIn'}))(SignupContainer)} />
|
component={ProxyHandler(AuthRedirect({to: '/collection', when: 'loggedIn'}))(SignupContainer)} />
|
||||||
|
Loading…
Reference in New Issue
Block a user