mirror of
https://github.com/scratchfoundation/scratch-www.git
synced 2025-02-25 05:44:13 -05:00
Show warning message when user has been muted several times.
This commit is contained in:
parent
338ac99e6b
commit
d8ad0c38ea
5 changed files with 85 additions and 6 deletions
|
@ -20,6 +20,10 @@ class MuteModal extends React.Component {
|
||||||
'handleNext',
|
'handleNext',
|
||||||
'handlePrevious'
|
'handlePrevious'
|
||||||
]);
|
]);
|
||||||
|
this.numSteps = 2;
|
||||||
|
if (this.props.showWarning) {
|
||||||
|
this.numSteps++;
|
||||||
|
}
|
||||||
this.state = {
|
this.state = {
|
||||||
step: 0
|
step: 0
|
||||||
};
|
};
|
||||||
|
@ -82,6 +86,23 @@ class MuteModal extends React.Component {
|
||||||
/>
|
/>
|
||||||
</p>
|
</p>
|
||||||
</MuteStep>
|
</MuteStep>
|
||||||
|
{this.props.showWarning ? (
|
||||||
|
<MuteStep
|
||||||
|
bottomImg="/svgs/commenting/warning.svg"
|
||||||
|
bottomImgClass="bottom-img"
|
||||||
|
header={this.props.intl.formatMessage({id: 'comments.muted.warningBlocked'})}
|
||||||
|
>
|
||||||
|
<p>
|
||||||
|
<FormattedMessage
|
||||||
|
id="comments.muted.warningCareful"
|
||||||
|
values={{CommunityGuidelinesLink: (
|
||||||
|
<a href="/community_guidelines">
|
||||||
|
<FormattedMessage id="report.CommunityGuidelinesLinkText" />
|
||||||
|
</a>
|
||||||
|
)}}
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
</MuteStep>) : null}
|
||||||
</Progression>
|
</Progression>
|
||||||
<FlexRow className={classNames('nav-divider')} />
|
<FlexRow className={classNames('nav-divider')} />
|
||||||
<FlexRow className={classNames('mute-nav')}>
|
<FlexRow className={classNames('mute-nav')}>
|
||||||
|
@ -97,7 +118,7 @@ class MuteModal extends React.Component {
|
||||||
</div>
|
</div>
|
||||||
</Button>
|
</Button>
|
||||||
) : null }
|
) : null }
|
||||||
{this.state.step >= 1 ? (
|
{this.state.step >= this.numSteps - 1 ? (
|
||||||
<Button
|
<Button
|
||||||
className={classNames('close-button')}
|
className={classNames('close-button')}
|
||||||
onClick={this.props.onRequestClose}
|
onClick={this.props.onRequestClose}
|
||||||
|
@ -131,6 +152,7 @@ MuteModal.propTypes = {
|
||||||
muteStepContent: PropTypes.string
|
muteStepContent: PropTypes.string
|
||||||
}),
|
}),
|
||||||
onRequestClose: PropTypes.func,
|
onRequestClose: PropTypes.func,
|
||||||
|
showWarning: PropTypes.bool,
|
||||||
timeMuted: PropTypes.string
|
timeMuted: PropTypes.string
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -354,6 +354,9 @@
|
||||||
"comments.muted.moreInfoGuidelines": "If you would like more information, you can read the {CommunityGuidelinesLink}.",
|
"comments.muted.moreInfoGuidelines": "If you would like more information, you can read the {CommunityGuidelinesLink}.",
|
||||||
"comments.muted.moreInfoModal": "For more information, {clickHereLink}.",
|
"comments.muted.moreInfoModal": "For more information, {clickHereLink}.",
|
||||||
"comments.muted.clickHereLinkText": "click here",
|
"comments.muted.clickHereLinkText": "click here",
|
||||||
|
"comments.muted.warningBlocked": "If you continue to post comments like this, it will cause you to be blocked from using Scratch",
|
||||||
|
"comments.muted.warningCareful": "We don't want that to happen, so please be careful and make sure you have read and understand the {CommunityGuidelinesLink} before you try to post again!",
|
||||||
|
|
||||||
|
|
||||||
"social.embedLabel": "Embed",
|
"social.embedLabel": "Embed",
|
||||||
"social.copyEmbedLinkText": "Copy embed",
|
"social.copyEmbedLinkText": "Copy embed",
|
||||||
|
|
|
@ -48,7 +48,8 @@ class ComposeComment extends React.Component {
|
||||||
error: null,
|
error: null,
|
||||||
appealId: null,
|
appealId: null,
|
||||||
muteOpen: false,
|
muteOpen: false,
|
||||||
muteExpiresAtMs: this.props.muteStatus.muteExpiresAt * 1000 // convert to ms
|
muteExpiresAtMs: this.props.muteStatus.muteExpiresAt * 1000, // convert to ms
|
||||||
|
showWarning: this.props.muteStatus.showWarning ? this.props.muteStatus.showWarning : false
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
handleInput (event) {
|
handleInput (event) {
|
||||||
|
@ -80,12 +81,14 @@ class ComposeComment extends React.Component {
|
||||||
let muteOpen = false;
|
let muteOpen = false;
|
||||||
let muteExpiresAtMs = 0;
|
let muteExpiresAtMs = 0;
|
||||||
let rejectedStatus = ComposeStatus.REJECTED;
|
let rejectedStatus = ComposeStatus.REJECTED;
|
||||||
|
let showWarning = false;
|
||||||
if (body.status && body.status.mute_status) {
|
if (body.status && body.status.mute_status) {
|
||||||
muteExpiresAtMs = body.status.mute_status.muteExpiresAt * 1000; // convert to ms
|
muteExpiresAtMs = body.status.mute_status.muteExpiresAt * 1000; // convert to ms
|
||||||
rejectedStatus = ComposeStatus.REJECTED_MUTE;
|
rejectedStatus = ComposeStatus.REJECTED_MUTE;
|
||||||
if (this.shouldShowMuteModal(body.status.mute_status.offenses)) {
|
if (this.shouldShowMuteModal(body.status.mute_status.offenses)) {
|
||||||
muteOpen = true;
|
muteOpen = true;
|
||||||
}
|
}
|
||||||
|
showWarning = body.status.mute_status.showWarning;
|
||||||
}
|
}
|
||||||
// Note: does not reset the message state
|
// Note: does not reset the message state
|
||||||
this.setState({
|
this.setState({
|
||||||
|
@ -93,7 +96,8 @@ class ComposeComment extends React.Component {
|
||||||
error: body.rejected,
|
error: body.rejected,
|
||||||
appealId: body.appealId,
|
appealId: body.appealId,
|
||||||
muteOpen: muteOpen,
|
muteOpen: muteOpen,
|
||||||
muteExpiresAtMs: muteExpiresAtMs
|
muteExpiresAtMs: muteExpiresAtMs,
|
||||||
|
showWarning: showWarning
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -287,6 +291,7 @@ class ComposeComment extends React.Component {
|
||||||
className="mod-mute"
|
className="mod-mute"
|
||||||
muteModalMessages={this.getMuteMessageInfo()}
|
muteModalMessages={this.getMuteMessageInfo()}
|
||||||
shouldCloseOnOverlayClick={false}
|
shouldCloseOnOverlayClick={false}
|
||||||
|
showWarning={this.state.showWarning}
|
||||||
timeMuted={formatTime.formatRelativeTime(this.state.muteExpiresAtMs, window._locale)}
|
timeMuted={formatTime.formatRelativeTime(this.state.muteExpiresAtMs, window._locale)}
|
||||||
onRequestClose={this.handleMuteClose}
|
onRequestClose={this.handleMuteClose}
|
||||||
/>
|
/>
|
||||||
|
@ -300,7 +305,8 @@ ComposeComment.propTypes = {
|
||||||
commenteeId: PropTypes.number,
|
commenteeId: PropTypes.number,
|
||||||
muteStatus: PropTypes.shape({
|
muteStatus: PropTypes.shape({
|
||||||
offenses: PropTypes.array,
|
offenses: PropTypes.array,
|
||||||
muteExpiresAt: PropTypes.number
|
muteExpiresAt: PropTypes.number,
|
||||||
|
showWarning: PropTypes.bool
|
||||||
}),
|
}),
|
||||||
onAddComment: PropTypes.func,
|
onAddComment: PropTypes.func,
|
||||||
onCancel: PropTypes.func,
|
onCancel: PropTypes.func,
|
||||||
|
@ -317,7 +323,7 @@ ComposeComment.propTypes = {
|
||||||
const mapStateToProps = state => ({
|
const mapStateToProps = state => ({
|
||||||
muteStatus: state.session.session.permissions.mute_status ?
|
muteStatus: state.session.session.permissions.mute_status ?
|
||||||
state.session.session.permissions.mute_status :
|
state.session.session.permissions.mute_status :
|
||||||
{muteExpiresAt: 0, offenses: []},
|
{muteExpiresAt: 0, offenses: [], showWarning: false},
|
||||||
user: state.session.session.user
|
user: state.session.session.user
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -104,7 +104,8 @@ describe('Compose Comment test', () => {
|
||||||
permissions: {
|
permissions: {
|
||||||
mute_status: {
|
mute_status: {
|
||||||
muteExpiresAt: 5,
|
muteExpiresAt: 5,
|
||||||
offenses: []
|
offenses: [],
|
||||||
|
showWarning: true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -114,6 +115,7 @@ describe('Compose Comment test', () => {
|
||||||
const commentInstance = component.instance();
|
const commentInstance = component.instance();
|
||||||
// Check conversion to ms from seconds is done at init time.
|
// Check conversion to ms from seconds is done at init time.
|
||||||
expect(commentInstance.state.muteExpiresAtMs).toEqual(5 * 1000);
|
expect(commentInstance.state.muteExpiresAtMs).toEqual(5 * 1000);
|
||||||
|
expect(commentInstance.state.showWarning).toBe(true);
|
||||||
// Compose box should be hidden if muted unless they got muted due to a comment they just posted.
|
// Compose box should be hidden if muted unless they got muted due to a comment they just posted.
|
||||||
expect(component.find('FlexRow.compose-comment').exists()).toEqual(false);
|
expect(component.find('FlexRow.compose-comment').exists()).toEqual(false);
|
||||||
expect(component.find('MuteModal').exists()).toEqual(false);
|
expect(component.find('MuteModal').exists()).toEqual(false);
|
||||||
|
@ -191,9 +193,41 @@ describe('Compose Comment test', () => {
|
||||||
commentInstance.setState({muteOpen: true});
|
commentInstance.setState({muteOpen: true});
|
||||||
component.update();
|
component.update();
|
||||||
expect(component.find('MuteModal').exists()).toEqual(true);
|
expect(component.find('MuteModal').exists()).toEqual(true);
|
||||||
|
expect(component.find('MuteModal').props().showWarning).toBe(false);
|
||||||
global.Date.now = realDateNow;
|
global.Date.now = realDateNow;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('Mute Modal gets showWarning props from state', () => {
|
||||||
|
const store = mockStore({
|
||||||
|
session: {
|
||||||
|
session: {
|
||||||
|
user: {},
|
||||||
|
permissions: {
|
||||||
|
mute_status: {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const component = mountWithIntl(
|
||||||
|
<ComposeComment
|
||||||
|
{...defaultProps()}
|
||||||
|
/>
|
||||||
|
, {context: {store}}
|
||||||
|
);
|
||||||
|
// set state on the ComposeComment component, not the wrapper
|
||||||
|
const commentInstance = component.find('ComposeComment').instance();
|
||||||
|
commentInstance.setState({muteOpen: true});
|
||||||
|
component.update();
|
||||||
|
expect(component.find('MuteModal').exists()).toEqual(true);
|
||||||
|
expect(component.find('MuteModal').props().showWarning).toBe(false);
|
||||||
|
commentInstance.setState({
|
||||||
|
muteOpen: true,
|
||||||
|
showWarning: true
|
||||||
|
});
|
||||||
|
component.update();
|
||||||
|
expect(component.find('MuteModal').props().showWarning).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
test('shouldShowMuteModal is false when list is undefined ', () => {
|
test('shouldShowMuteModal is false when list is undefined ', () => {
|
||||||
const commentInstance = getComposeCommentWrapper({}).instance();
|
const commentInstance = getComposeCommentWrapper({}).instance();
|
||||||
expect(commentInstance.shouldShowMuteModal()).toBe(false);
|
expect(commentInstance.shouldShowMuteModal()).toBe(false);
|
||||||
|
|
|
@ -33,6 +33,20 @@ describe('MuteModalTest', () => {
|
||||||
expect(component.find('button.back-button').exists()).toEqual(false);
|
expect(component.find('button.back-button').exists()).toEqual(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('Mute Modal shows extra showWarning step', () => {
|
||||||
|
const component = mountWithIntl(
|
||||||
|
<MuteModal
|
||||||
|
showWarning
|
||||||
|
muteModalMessages={defaultMessages}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
component.find('MuteModal').instance()
|
||||||
|
.setState({step: 2});
|
||||||
|
component.update();
|
||||||
|
expect(component.find('MuteStep').prop('bottomImg')).toEqual('/svgs/commenting/warning.svg');
|
||||||
|
expect(component.find('MuteStep').prop('totalSteps')).toEqual(3);
|
||||||
|
});
|
||||||
|
|
||||||
test('Mute Modal shows back & close button on last step', () => {
|
test('Mute Modal shows back & close button on last step', () => {
|
||||||
const component = mountWithIntl(
|
const component = mountWithIntl(
|
||||||
<MuteModal muteModalMessages={defaultMessages} />
|
<MuteModal muteModalMessages={defaultMessages} />
|
||||||
|
|
Loading…
Reference in a new issue