Break up HeaderNotifications into stateless components and pass props down to MenuItems

React-bootstrap Dropdowns expect that passed down props will reach
their MenuItems in order for event callbacks to be triggered (ie. auto
closing the dropdown on select).
This commit is contained in:
Brett Sun 2016-06-17 14:17:53 +02:00
parent 388e10471b
commit f775222768
1 changed files with 83 additions and 88 deletions

View File

@ -1,10 +1,7 @@
'use strict';
import React from 'react';
import Glyphicon from 'react-bootstrap/lib/Glyphicon';
import MenuItem from 'react-bootstrap/lib/MenuItem';
import Nav from 'react-bootstrap/lib/Nav';
import NavDropdown from 'react-bootstrap/lib/NavDropdown';
import LinkContainer from 'react-router-bootstrap/lib/LinkContainer';
@ -18,11 +15,89 @@ import { currentUserShape } from './prop_types';
import { getLangText } from '../utils/lang';
let HeaderNotifications = React.createClass({
const { array, bool, object } = React.PropTypes;
const NotificationList = ({ isPiece, notifications, ...props }) => {
if (notifications.length) {
return (
<div>
<div className="notification-header">
{`${(isPiece ? 'Artworks' : 'Editions')} (${notifications.length})`}
</div>
{notifications.map((notification) => {
const pieceOrEdition = isPiece ? notification.piece : notification.edition;
const href = isPiece ? `/pieces/${pieceOrEdition.id}`
: `/editions/${pieceOrEdition.bitcoin_id}`;
if (pieceOrEdition && notification.notification) {
return (
<LinkContainer {...props} key={href} to={href}>
<MenuItem>
<NotificationListItem
notifications={notification.notification}
pieceOrEdition={pieceOrEdition} />
</MenuItem>
</LinkContainer>
);
} else {
return null;
}
})}
</div>
);
} else {
return null;
}
};
NotificationList.propTypes = {
notifications: array.isRequired,
isPiece: bool
};
const NotificationListItem = ({ notifications, pieceOrEdition }) => (
<div className="row notification-wrapper">
<div className="col-xs-4 clear-paddings thumbnail-wrapper">
<img role="presentation" src={pieceOrEdition.thumbnail.url_safe} />
</div>
<div className="col-xs-8 notification-list-item-header">
<h1>{pieceOrEdition.title}</h1>
<div className="sub-header">by {pieceOrEdition.artist_name}</div>
<NotificationAction notifications={notifications} />
</div>
</div>
);
NotificationListItem.propTypes = {
notifications: array.isRequired,
pieceOrEdition: object.isRequired
};
const NotificationAction = ({ notifications }) => {
const additionalNotifications = notifications.length > 1 ? (
<div>
+ {notifications.length - 1} {getLangText('more...')}
</div>
) : null;
return (
<div className="notification-action">
{notifications[0].action_str}
{additionalNotifications}
</div>
);
};
NotificationAction.propTypes = {
notifications: array.isRequired,
};
const HeaderNotifications = React.createClass({
propTypes: {
// Injected through HOCs
currentUser: currentUserShape.isRequired, // eslint-disable-line react/sort-prop-types
isLoggedIn: React.PropTypes.bool.isRequired // eslint-disable-line react/sort-prop-types
currentUser: currentUserShape.isRequired,
isLoggedIn: bool.isRequired
},
getInitialState() {
@ -56,35 +131,6 @@ let HeaderNotifications = React.createClass({
NotificationActions.fetchEditionListNotifications();
},
renderNotifications({ notifications, isPiece }) {
if (notifications.length) {
return (
<div>
<div className="notification-header">
{`${(isPiece ? 'Artworks' : 'Editions')} (${notifications.length})`}
</div>
{notifications.map((notification) => {
const pieceOrEdition = isPiece ? notification.piece : notification.edition;
const href = isPiece ? `/pieces/${pieceOrEdition.id}`
: `/editions/${pieceOrEdition.bitcoin_id}`;
return (
<LinkContainer key={href} to={href}>
<MenuItem>
<NotificationListItem
notification={notification.notification}
pieceOrEdition={pieceOrEdition} />
</MenuItem>
</LinkContainer>
);
})}
</div>
);
} else {
return null;
}
},
render() {
const { editionListNotifications, pieceListNotifications } = this.state;
if (pieceListNotifications.length || editionListNotifications.length) {
@ -108,14 +154,8 @@ let HeaderNotifications = React.createClass({
<span className="notification-amount">({numNotifications})</span>
</span>
}>
{this.renderNotifications({
notifications: pieceListNotifications,
isPiece: true
})}
{this.renderNotifications({
notifications: editionListNotifications,
isPiece: false
})}
<NotificationList isPiece notifications={pieceListNotifications} />
<NotificationList notifications={editionListNotifications} />
</NavDropdown>
);
}
@ -123,49 +163,4 @@ let HeaderNotifications = React.createClass({
}
});
let NotificationListItem = React.createClass({
propTypes: {
notification: React.PropTypes.array,
pieceOrEdition: React.PropTypes.object,
},
getNotificationText() {
let numNotifications = null;
if (this.props.notification.length > 1) {
numNotifications = (
<div>
+ {this.props.notification.length - 1} {getLangText('more...')}
</div>
);
}
return (
<div className="notification-action">
{this.props.notification[0].action_str}
{numNotifications}
</div>);
},
render() {
const { pieceOrEdition } = this.props;
if (pieceOrEdition) {
return (
<div className="row notification-wrapper">
<div className="col-xs-4 clear-paddings">
<div className="thumbnail-wrapper">
<img role="presentation" src={pieceOrEdition.thumbnail.url_safe} />
</div>
</div>
<div className="col-xs-8 notification-list-item-header">
<h1>{pieceOrEdition.title}</h1>
<div className="sub-header">by {pieceOrEdition.artist_name}</div>
{this.getNotificationText()}
</div>
</div>
);
}
return null;
}
});
export default withContext(HeaderNotifications, 'currentUser', 'isLoggedIn');