Merge pull request #4655 from picklesrus/use-minutes

Disable comment box functionality when you've just been muted.
This commit is contained in:
picklesrus 2020-11-25 10:18:41 -05:00 committed by GitHub
commit 0f83b0c7c8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 98 additions and 8 deletions

View file

@ -275,6 +275,10 @@
} }
} }
.compose-disabled {
opacity: .5;
}
.comments-root-reply { .comments-root-reply {
margin-bottom: 1.5rem; margin-bottom: 1.5rem;
} }

View file

@ -38,8 +38,8 @@ class ComposeComment extends React.Component {
'handleCancel', 'handleCancel',
'handleInput', 'handleInput',
'handleMuteClose', 'handleMuteClose',
'handleMuteOpen' 'handleMuteOpen',
'isMuted'
]); ]);
this.state = { this.state = {
message: '', message: '',
@ -115,6 +115,10 @@ class ComposeComment extends React.Component {
return Math.ceil(((timeStampInSec * 1000) - Date.now()) / (60 * 1000)); return Math.ceil(((timeStampInSec * 1000) - Date.now()) / (60 * 1000));
} }
isMuted () {
return this.state.muteExpiresAt * 1000 > Date.now();
}
handleMuteClose () { handleMuteClose () {
this.setState({ this.setState({
muteOpen: false muteOpen: false
@ -163,10 +167,10 @@ class ComposeComment extends React.Component {
render () { render () {
return ( return (
<React.Fragment> <React.Fragment>
{this.state.status === ComposeStatus.REJECTED_MUTE ? ( {this.isMuted() ? (
<FlexRow className="comment"> <FlexRow className="comment">
<CommentingStatus> <CommentingStatus>
<p>Scratch thinks your comment was disrespectful.</p> <p>Scratch thinks your most recent comment was disrespectful.</p>
<p> <p>
For the next {this.convertToMinutesFromNow(this.state.muteExpiresAt)} minutes you For the next {this.convertToMinutesFromNow(this.state.muteExpiresAt)} minutes you
won&apos;t be able to post comments. won&apos;t be able to post comments.
@ -182,7 +186,10 @@ class ComposeComment extends React.Component {
</FlexRow> </FlexRow>
) : null } ) : null }
<div <div
className="flex-row comment" className={classNames('flex-row',
'comment',
this.state.status === ComposeStatus.REJECTED_MUTE ?
'compose-disabled' : '')}
> >
<a href={`/users/${this.props.user.username}`}> <a href={`/users/${this.props.user.username}`}>
<Avatar src={this.props.user.thumbnailUrl} /> <Avatar src={this.props.user.thumbnailUrl} />
@ -205,6 +212,7 @@ class ComposeComment extends React.Component {
className={classNames('compose-input', className={classNames('compose-input',
MAX_COMMENT_LENGTH - this.state.message.length >= 0 ? MAX_COMMENT_LENGTH - this.state.message.length >= 0 ?
'compose-valid' : 'compose-invalid')} 'compose-valid' : 'compose-invalid')}
disabled={this.state.status === ComposeStatus.REJECTED_MUTE}
handleUpdate={onUpdate} handleUpdate={onUpdate}
name="compose-comment" name="compose-comment"
type="textarea" type="textarea"

View file

@ -66,23 +66,73 @@ describe('Compose Comment test', () => {
expect(component.find('FlexRow.compose-error-row').exists()).toEqual(false); expect(component.find('FlexRow.compose-error-row').exists()).toEqual(false);
}); });
test('Comment Status shows when state is REJECTED_MUTE ', () => { test('Comment Status shows when mute expiration in the future ', () => {
const realDateNow = Date.now.bind(global.Date);
global.Date.now = () => 0;
const component = getComposeCommentWrapper({}); const component = getComposeCommentWrapper({});
const commentInstance = component.instance(); const commentInstance = component.instance();
commentInstance.setState({status: 'REJECTED_MUTE'}); commentInstance.setState({muteExpiresAt: 100});
component.update(); component.update();
expect(component.find('FlexRow.compose-comment').exists()).toEqual(true); expect(component.find('FlexRow.compose-comment').exists()).toEqual(true);
expect(component.find('MuteModal').exists()).toEqual(false); expect(component.find('MuteModal').exists()).toEqual(false);
expect(component.find('CommentingStatus').exists()).toEqual(true); expect(component.find('CommentingStatus').exists()).toEqual(true);
global.Date.now = realDateNow;
});
test('Comment Status shows when user just submitted a comment that got them muted', () => {
const realDateNow = Date.now.bind(global.Date);
global.Date.now = () => 0;
const component = getComposeCommentWrapper({});
const commentInstance = component.instance();
commentInstance.setState({
status: 'REJECTED_MUTE',
muteExpiresAt: 100
});
component.update();
expect(component.find('FlexRow.compose-comment').exists()).toEqual(true);
expect(component.find('MuteModal').exists()).toEqual(false);
expect(component.find('CommentingStatus').exists()).toEqual(true);
// Compose box is disabled
expect(component.find('InplaceInput.compose-input').exists()).toEqual(true);
expect(component.find('InplaceInput.compose-input').props().disabled).toBe(true);
global.Date.now = realDateNow;
});
test('Comment Error does not show for mutes', () => {
const realDateNow = Date.now.bind(global.Date);
global.Date.now = () => 0;
const component = getComposeCommentWrapper({});
const commentInstance = component.instance();
commentInstance.setState({
status: 'REJECTED_MUTE',
error: 'a mute error'
});
component.update();
expect(component.find('FlexRow.compose-error-row').exists()).toEqual(false);
expect(component.find('FlexRow.compose-comment').exists()).toEqual(true);
global.Date.now = realDateNow;
});
test('Comment Error does show for non-mute errors', () => {
const component = getComposeCommentWrapper({});
const commentInstance = component.instance();
commentInstance.setState({
error: 'some error',
status: 'FLOOD'
});
component.update();
expect(component.find('FlexRow.compose-error-row').exists()).toEqual(true);
expect(component.find('FlexRow.compose-comment').exists()).toEqual(true);
expect(component.find('InplaceInput.compose-input').exists()).toEqual(true);
expect(component.find('InplaceInput.compose-input').props().disabled).toBe(false);
}); });
test('Mute Modal shows when muteOpen is true ', () => { test('Mute Modal shows when muteOpen is true ', () => {
const realDateNow = Date.now.bind(global.Date);
global.Date.now = () => 0;
const component = getComposeCommentWrapper({}); const component = getComposeCommentWrapper({});
const commentInstance = component.instance(); const commentInstance = component.instance();
commentInstance.setState({muteOpen: true}); commentInstance.setState({muteOpen: true});
component.update(); component.update();
expect(component.find('FlexRow.compose-comment').exists()).toEqual(true);
expect(component.find('MuteModal').exists()).toEqual(true); expect(component.find('MuteModal').exists()).toEqual(true);
global.Date.now = realDateNow;
}); });
test('shouldShowMuteModal is false when list is undefined ', () => { test('shouldShowMuteModal is false when list is undefined ', () => {
@ -130,4 +180,32 @@ describe('Compose Comment test', () => {
global.Date.now = realDateNow; global.Date.now = realDateNow;
}); });
test('isMuted: expiration is in the future ', () => {
const realDateNow = Date.now.bind(global.Date);
global.Date.now = () => 0; // Set "now" to 0 for easier testing.
const commentInstance = getComposeCommentWrapper({}).instance();
commentInstance.setState({muteExpiresAt: 100});
expect(commentInstance.isMuted()).toBe(true);
global.Date.now = realDateNow;
});
test('isMuted: expiration is in the past ', () => {
const realDateNow = Date.now.bind(global.Date);
global.Date.now = () => 0;
const commentInstance = getComposeCommentWrapper({}).instance();
commentInstance.setState({muteExpiresAt: -100});
expect(commentInstance.isMuted()).toBe(false);
global.Date.now = realDateNow;
});
test('isMuted: expiration is not set ', () => {
const realDateNow = Date.now.bind(global.Date);
global.Date.now = () => 0;
const commentInstance = getComposeCommentWrapper({}).instance();
expect(commentInstance.isMuted()).toBe(false);
global.Date.now = realDateNow;
});
}); });