Introduce comment thread limit on studio comments. When a user clicks reply on a thread that has reached the limit, display a comment status message in place of the comment composer. The user should only see one status box in a message thread.

This commit is contained in:
Karishma Chadha 2021-05-25 23:11:17 -04:00
parent 460010e64f
commit e57cd9a111
5 changed files with 96 additions and 23 deletions

View file

@ -338,6 +338,7 @@
"comments.cancel": "Cancel",
"comments.lengthWarning": "{remainingCharacters, plural, one {1 character left} other {{remainingCharacters} characters left}}",
"comments.loadMoreReplies": "See more replies",
"comments.reachedThreadLimit": "This comment thread has reached its limit. To continue commenting, you can start a new thread.",
"comments.status.delbyusr": "Deleted by project owner",
"comments.status.censbyfilter": "Censored by filter",
"comments.status.delbyparentcomment": "Parent comment deleted",

View file

@ -26,6 +26,7 @@ class Comment extends React.Component {
'handleConfirmReport',
'handleCancelReport',
'handlePostReply',
'handleReply',
'handleToggleReplying',
'handleRestore',
'setRef'
@ -49,6 +50,14 @@ class Comment extends React.Component {
this.props.onAddComment(comment);
}
handleReply () {
if (this.props.hasReachedThreadLimit) {
this.props.onReply(this.props.id, (this.props.parentId || this.props.id));
} else {
this.handleToggleReplying();
}
}
handleToggleReplying () {
this.setState({replying: !this.state.replying});
}
@ -220,7 +229,7 @@ class Comment extends React.Component {
{(canReply && visible) ? (
<span
className="comment-reply"
onClick={this.handleToggleReplying}
onClick={this.handleReply}
>
<FormattedMessage id="comments.reply" />
</span>
@ -278,10 +287,12 @@ Comment.propTypes = {
canRestore: PropTypes.bool,
content: PropTypes.string,
datetimeCreated: PropTypes.string,
hasReachedThreadLimit: PropTypes.bool,
highlighted: PropTypes.bool,
id: PropTypes.number,
onAddComment: PropTypes.func,
onDelete: PropTypes.func,
onReply: PropTypes.func,
onReport: PropTypes.func,
onRestore: PropTypes.func,
parentId: PropTypes.number,

View file

@ -279,6 +279,15 @@
}
}
.thread-limit-status {
width: calc(100% - 10rem);
margin-left: auto;
.comment-status-icon {
display: none;
}
}
.compose-disabled {
opacity: .5;
}

View file

@ -6,9 +6,13 @@ const FormattedMessage = require('react-intl').FormattedMessage;
const FlexRow = require('../../../components/flex-row/flex-row.jsx');
const Comment = require('./comment.jsx');
const CommentingStatus = require('../../../components/commenting-status/commenting-status.jsx');
require('./comment.scss');
// Thread limit only applies if hasThreadLimit prop is true
const THREAD_LIMIT = 25;
class TopLevelComment extends React.Component {
constructor (props) {
super(props);
@ -16,11 +20,14 @@ class TopLevelComment extends React.Component {
'handleExpandThread',
'handleAddComment',
'handleDeleteReply',
'handleReplyStatus',
'handleReportReply',
'handleRestoreReply'
]);
this.state = {
expanded: this.props.defaultExpanded
expanded: this.props.defaultExpanded,
threadLimitCommentId: '',
threadLimitParentId: ''
};
// A cache of {userId: username, ...} in order to show reply usernames
@ -55,6 +62,10 @@ class TopLevelComment extends React.Component {
this.props.onAddComment(comment, this.props.id);
}
handleReplyStatus (id, parentId) {
this.setState({threadLimitCommentId: id, threadLimitParentId: parentId});
}
authorUsername (authorId) {
if (this.authorUsernameCache[authorId]) return this.authorUsernameCache[authorId];
@ -80,6 +91,7 @@ class TopLevelComment extends React.Component {
canRestore,
content,
datetimeCreated,
hasThreadLimit,
highlightedCommentId,
id,
moreRepliesToLoad,
@ -93,12 +105,28 @@ class TopLevelComment extends React.Component {
const parentVisible = visibility === 'visible';
// Check whether this comment thread has reached the thread limit
const hasReachedThreadLimit = hasThreadLimit && replies.length >= THREAD_LIMIT;
/*
Check all the following conditions:
- hasReachedThreadLimit: the thread has reached the limit
- Use the comment id and parent id of this particular comment in this thread
to see if it has the reply status,
only one comment in a thread can have the status
*/
const commentHasReplyStatus = (commentId, commentParentId) =>
hasReachedThreadLimit &&
(this.state.threadLimitCommentId === commentId) &&
(this.state.threadLimitParentId === commentParentId);
return (
<FlexRow className="comment-container">
<Comment
highlighted={highlightedCommentId === id}
postURI={postURI}
onAddComment={this.handleAddComment}
onReply={this.handleReplyStatus}
{...{
author,
content,
@ -108,6 +136,7 @@ class TopLevelComment extends React.Component {
canReply,
canReport,
canRestore,
hasReachedThreadLimit,
id,
onDelete,
onReport,
@ -115,6 +144,13 @@ class TopLevelComment extends React.Component {
visibility
}}
/>
{commentHasReplyStatus(id, id) &&
<CommentingStatus className="thread-limit-status">
<p>
<FormattedMessage id="comments.reachedThreadLimit" />
</p>
</CommentingStatus>
}
{replies.length > 0 &&
<FlexRow
className={classNames(
@ -125,27 +161,40 @@ class TopLevelComment extends React.Component {
key={id}
>
{(this.state.expanded ? replies : replies.slice(0, 3)).map(reply => (
<Comment
author={reply.author}
canDelete={canDelete}
canDeleteWithoutConfirm={canDeleteWithoutConfirm}
canReply={canReply}
canReport={canReport}
canRestore={canRestore && parentVisible}
content={reply.content}
datetimeCreated={reply.datetime_created}
highlighted={highlightedCommentId === reply.id}
id={reply.id}
key={reply.id}
parentId={id}
postURI={postURI}
replyUsername={this.authorUsername(reply.commentee_id)}
visibility={reply.visibility}
onAddComment={this.handleAddComment}
onDelete={this.handleDeleteReply}
onReport={this.handleReportReply}
onRestore={this.handleRestoreReply}
/>
<React.Fragment
key={`reply-and-status-${reply.id}`}
>
<Comment
author={reply.author}
canDelete={canDelete}
canDeleteWithoutConfirm={canDeleteWithoutConfirm}
canReply={canReply}
canReport={canReport}
canRestore={canRestore && parentVisible}
content={reply.content}
datetimeCreated={reply.datetime_created}
hasReachedThreadLimit={hasReachedThreadLimit}
highlighted={highlightedCommentId === reply.id}
id={reply.id}
key={reply.id}
parentId={id}
postURI={postURI}
replyUsername={this.authorUsername(reply.commentee_id)}
visibility={reply.visibility}
onAddComment={this.handleAddComment}
onDelete={this.handleDeleteReply}
onReply={this.handleReplyStatus}
onReport={this.handleReportReply}
onRestore={this.handleRestoreReply}
/>
{commentHasReplyStatus(reply.id, id) &&
<CommentingStatus className="thread-limit-status">
<p>
<FormattedMessage id="comments.reachedThreadLimit" />
</p>
</CommentingStatus>
}
</React.Fragment>
))}
{((!this.state.expanded && replies.length > 3) ||
(this.state.expanded && moreRepliesToLoad)) &&
@ -179,6 +228,7 @@ TopLevelComment.propTypes = {
datetimeCreated: PropTypes.string,
defaultExpanded: PropTypes.bool,
deletable: PropTypes.bool,
hasThreadLimit: PropTypes.bool,
highlightedCommentId: PropTypes.oneOfType([PropTypes.number, PropTypes.bool]),
id: PropTypes.number,
moreRepliesToLoad: PropTypes.bool,
@ -196,6 +246,7 @@ TopLevelComment.propTypes = {
TopLevelComment.defaultProps = {
canDeleteWithoutConfirm: false,
defaultExpanded: false,
hasThreadLimit: false,
moreRepliesToLoad: false
};

View file

@ -69,6 +69,7 @@ const StudioComments = ({
}
{comments.map(comment => (
<TopLevelComment
hasThreadLimit
author={comment.author}
canDelete={canDeleteComment}
canDeleteWithoutConfirm={canDeleteCommentWithoutConfirm}