scratch-www/src/views/messages/presentation.jsx
carljbowman 12c0706dbb Modify load more button
With box-shadows being removed from buttons there were a few places that needed to be adjusted: white buttons on light gray backdrop
2018-07-16 18:06:15 -04:00

390 lines
16 KiB
JavaScript

const bindAll = require('lodash.bindall');
const FormattedMessage = require('react-intl').FormattedMessage;
const FormattedNumber = require('react-intl').FormattedNumber;
const injectIntl = require('react-intl').injectIntl;
const intlShape = require('react-intl').intlShape;
const PropTypes = require('prop-types');
const React = require('react');
const Button = require('../../components/forms/button.jsx');
const FlexRow = require('../../components/flex-row/flex-row.jsx');
const Form = require('../../components/forms/form.jsx');
const Select = require('../../components/forms/select.jsx');
const TitleBanner = require('../../components/title-banner/title-banner.jsx');
const messageStatuses = require('../../redux/messages').Status;
// Message Components
const AdminMessage = require('./message-rows/admin-message.jsx');
const BecomeManagerMessage = require('./message-rows/become-manager.jsx');
const CommentMessage = require('./message-rows/comment-message.jsx');
const CuratorInviteMessage = require('./message-rows/curator-invite.jsx');
const FavoriteProjectMessage = require('./message-rows/favorite-project.jsx');
const FollowUserMessage = require('./message-rows/follow-user.jsx');
const ForumPostMessage = require('./message-rows/forum-topic-post.jsx');
const LoveProjectMessage = require('./message-rows/love-project.jsx');
const RemixProjectMessage = require('./message-rows/remix-project.jsx');
const ScratcherInvite = require('./message-rows/scratcher-invite.jsx');
const StudioActivityMessage = require('./message-rows/studio-activity.jsx');
const UserJoinMessage = require('./message-rows/user-join.jsx');
require('./messages.scss');
class SocialMessagesList extends React.Component {
constructor (props) {
super(props);
bindAll(this, [
'getComponentForMessage',
'renderLoadMore',
'renderMessageCounter'
]);
}
getComponentForMessage (message, unread) {
const className = (unread) ? 'mod-unread' : '';
const key = `${message.type}_ ${message.id}`;
switch (message.type) {
case 'followuser':
return (
<FollowUserMessage
className={className}
followDateTime={message.datetime_created}
followerUsername={message.actor_username}
key={key}
/>
);
case 'loveproject':
return (
<LoveProjectMessage
actorUsername={message.actor_username}
className={className}
key={key}
loveDateTime={message.datetime_created}
projectId={message.project_id}
projectTitle={message.title}
/>
);
case 'favoriteproject':
return (
<FavoriteProjectMessage
actorUsername={message.actor_username}
className={className}
favoriteDateTime={message.datetime_created}
key={key}
projectId={message.project_id}
projectTitle={message.project_title}
/>
);
case 'addcomment':
return (
<CommentMessage
actorId={message.actor_id}
actorUsername={message.actor_username}
className={className}
commentDateTime={message.datetime_created}
commentId={message.comment_id}
commentText={message.comment_fragment}
commentee={message.commentee_username}
key={key}
objectId={message.comment_obj_id}
objectTitle={message.comment_obj_title}
objectType={message.comment_type}
/>
);
case 'curatorinvite':
return (
<CuratorInviteMessage
actorUsername={message.actor_username}
className={className}
datetimePromoted={message.datetime_created}
key={key}
studioId={message.gallery_id}
studioTitle={message.title}
/>
);
case 'remixproject':
return (
<RemixProjectMessage
actorUsername={message.actor_username}
className={className}
key={key}
parentId={message.parent_id}
parentTitle={message.parent_title}
projectId={message.project_id}
projectTitle={message.title}
remixDate={message.datetime_created}
/>
);
case 'studioactivity':
return (
<StudioActivityMessage
className={className}
datetimeCreated={message.datetime_created}
key={key}
studioId={message.gallery_id}
studioTitle={message.title}
/>
);
case 'forumpost':
return (
<ForumPostMessage
actorUsername={message.actor_username}
className={className}
datetimeCreated={message.datetime_created}
key={key}
topicId={message.topic_id}
topicTitle={message.topic_title}
/>
);
case 'becomeownerstudio':
return (
<BecomeManagerMessage
actorUsername={message.actor_username}
className={className}
datetimePromoted={message.datetime_created}
key={key}
studioId={message.gallery_id}
studioTitle={message.gallery_title}
/>
);
case 'userjoin':
return (
<UserJoinMessage
className={className}
datetimeJoined={message.datetime_created}
key={key}
/>
);
}
}
renderLoadMore (loadMore) {
if (loadMore) {
return (
<Button
className="messages-social-loadmore"
key="load-more"
onClick={this.props.onLoadMoreMethod}
>
<FormattedMessage id="general.loadMore" />
</Button>
);
}
return null;
}
renderMessageCounter (numNewMessages) {
if (numNewMessages > 0) {
return (
<div className="messages-header-unread">
<FormattedNumber value={numNewMessages} />
</div>
);
}
return null;
}
render () {
if (this.props.loadStatus === messageStatuses.MESSAGES_ERROR) {
return (
<section className="messages-social">
<div className="messages-social-title">
<h4>
<FormattedMessage id="messages.messageTitle" />
</h4>
</div>
<p><FormattedMessage id="messages.requestError" /></p>
</section>
);
}
return (
<section className="messages-social">
{this.props.messages.length > 0 ? [
<div
className="messages-social-title"
key="messages-social-title"
>
<h4 className="messages-header">
<FormattedMessage id="messages.messageTitle" />
{this.renderMessageCounter(this.props.numNewMessages)}
</h4>
</div>,
<ul
className="messages-social-list"
key="messages-social-list"
>
{this.props.messages.map((message, messageId) => {
if (messageId < this.props.numNewMessages) {
return this.getComponentForMessage(message, true);
}
return this.getComponentForMessage(message, false);
})}
</ul>
] : []}
{this.renderLoadMore(this.props.loadMore)}
</section>
);
}
}
SocialMessagesList.propTypes = {
loadMore: PropTypes.bool.isRequired,
loadStatus: PropTypes.string,
messages: PropTypes.arrayOf(PropTypes.object).isRequired,
numNewMessages: PropTypes.number,
onLoadMoreMethod: PropTypes.func
};
SocialMessagesList.defaultProps = {
loadStatus: messageStatuses.FETCHING,
numNewMessages: 0
};
const MessagesPresentation = props => {
let adminMessageLength = props.adminMessages.length;
if (Object.keys(props.scratcherInvite).length > 0) {
adminMessageLength = adminMessageLength + 1;
}
let numNewSocialMessages = props.numNewMessages - adminMessageLength;
if (numNewSocialMessages < 0) {
numNewSocialMessages = 0;
}
return (
<div className="messages">
<TitleBanner className="mod-messages">
<FlexRow className="inner mod-messages-title">
<h1 className="title-banner-h1 mod-messages">
<FormattedMessage id="messages.messageTitle" />
</h1>
<div className="messages-title-filter">
<Form>
<Select
label={props.intl.formatMessage({id: 'messages.filterBy'})}
name="messages.filter"
options={[
{
label: props.intl.formatMessage({id: 'messages.activityAll'}),
value: ''
},
{
label: props.intl.formatMessage({id: 'messages.activityComments'}),
value: 'comments'
},
{
label: props.intl.formatMessage({id: 'messages.activityProjects'}),
value: 'projects'
},
{
label: props.intl.formatMessage({id: 'messages.activityStudios'}),
value: 'studios'
},
{
label: props.intl.formatMessage({id: 'messages.activityForums'}),
value: 'forums'
}
]}
value={props.filter}
onChange={props.onFilterClick}
/>
</Form>
</div>
</FlexRow>
</TitleBanner>
<div className="messages-details inner">
{props.adminMessages.length > 0 || Object.keys(props.scratcherInvite).length > 0 ? [
<section
className="messages-admin"
key="messages-admin"
>
<div className="messages-admin-title">
<h4 className="messages-header">
<FormattedMessage id="messages.scratchTeamTitle" />
<div className="messages-header-unread">
<FormattedNumber value={adminMessageLength} />
</div>
</h4>
</div>
<ul className="messages-admin-list">
{Object.keys(props.scratcherInvite).length > 0 ? [
<ScratcherInvite
datetimeCreated={props.scratcherInvite.datetime_created}
id={props.scratcherInvite.id}
key={`invite${props.scratcherInvite.id}`}
username={props.user.username}
onDismiss={() => { // eslint-disable-line react/jsx-no-bind
props.onAdminDismiss('invite', props.scratcherInvite.id);
}}
/>
] : []}
{props.adminMessages.map(item => (
<AdminMessage
datetimeCreated={item.datetime_created}
id={item.id}
key={`adminmessage${item.id}`}
message={item.message}
onDismiss={() => { // eslint-disable-line react/jsx-no-bind
props.onAdminDismiss('notification', item.id);
}}
/>
))}
</ul>
</section>
] : []}
{props.requestStatus.admin === messageStatuses.ADMIN_ERROR ? [
<section
className="messages-admin"
key="messages-admin-error"
>
<h4>
<FormattedMessage id="messages.scratchTeamTitle" />
</h4>
<p><FormattedMessage id="messages.requestError" /></p>
</section>
] : []}
<SocialMessagesList
loadMore={props.loadMore}
loadStatus={props.requestStatus.message}
messages={props.messages}
numNewMessages={numNewSocialMessages}
onLoadMoreMethod={props.onLoadMoreMethod}
/>
</div>
</div>
);
};
MessagesPresentation.propTypes = {
adminMessages: PropTypes.arrayOf(PropTypes.object).isRequired,
filter: PropTypes.string,
intl: intlShape,
loadMore: PropTypes.bool.isRequired,
messages: PropTypes.arrayOf(PropTypes.object).isRequired,
numNewMessages: PropTypes.number,
onAdminDismiss: PropTypes.func.isRequired,
onFilterClick: PropTypes.func.isRequired,
onLoadMoreMethod: PropTypes.func,
requestStatus: PropTypes.shape({
admin: PropTypes.string,
clear: PropTypes.string,
message: PropTypes.string,
delete: PropTypes.string
}).isRequired,
scratcherInvite: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
user: PropTypes.shape({
id: PropTypes.number,
banned: PropTypes.bool,
username: PropTypes.string,
token: PropTypes.string,
thumbnailUrl: PropTypes.string,
dateJoined: PropTypes.string,
email: PropTypes.string,
classroomId: PropTypes.string
}).isRequired
};
MessagesPresentation.defaultProps = {
filter: '',
filterOpen: false,
numNewMessages: 0
};
module.exports = injectIntl(MessagesPresentation);