mirror of
https://github.com/scratchfoundation/scratch-www.git
synced 2024-11-23 15:47:53 -05:00
Pass a customized comment component for studios
This commit is contained in:
parent
fced16b08c
commit
cfd52d9369
6 changed files with 49 additions and 35 deletions
|
@ -18,14 +18,18 @@ const selectCanAddProjects = state =>
|
||||||
// This isn't "canComment" since they could be muted, but comment composer handles that
|
// This isn't "canComment" since they could be muted, but comment composer handles that
|
||||||
const selectShowCommentComposer = state => selectIsSocial(state);
|
const selectShowCommentComposer = state => selectIsSocial(state);
|
||||||
|
|
||||||
const selectCanReportComment = state => selectIsSocial(state);
|
const selectCanReportComment = (state, commentUsername) =>
|
||||||
|
selectIsLoggedIn(state) && selectUsername(state) !== commentUsername;
|
||||||
const selectCanRestoreComment = state => selectIsAdmin(state);
|
const selectCanRestoreComment = state => selectIsAdmin(state);
|
||||||
// On the project page, project owners can delete comments with a confirmation,
|
// On the project page, project owners can delete comments with a confirmation,
|
||||||
// and admins can delete comments without a confirmation.
|
// and admins can delete comments without a confirmation.
|
||||||
// On the studio page, studio creators and managers have the ability to delete *their own* comments with confirmation.
|
// On the studio page, studio creators and managers have the ability to delete *their own* comments with confirmation.
|
||||||
// Admins can delete comments without a confirmation.
|
// Admins can delete comments without a confirmation.
|
||||||
const selectCanDeleteAnyComment = state => selectIsAdmin(state);
|
const selectCanDeleteComment = (state, commentUsername) => {
|
||||||
const selectCanDeleteOwnComment = state => isCreator(state) || isManager(state);
|
if (selectIsAdmin(state)) return true;
|
||||||
|
if (isManager(state) && selectUsername(state) === commentUsername) return true;
|
||||||
|
return false;
|
||||||
|
};
|
||||||
const selectCanDeleteCommentWithoutConfirm = state => selectIsAdmin(state);
|
const selectCanDeleteCommentWithoutConfirm = state => selectIsAdmin(state);
|
||||||
|
|
||||||
const selectCanFollowStudio = state => selectIsLoggedIn(state);
|
const selectCanFollowStudio = state => selectIsLoggedIn(state);
|
||||||
|
@ -82,8 +86,7 @@ export {
|
||||||
selectCanAddProjects,
|
selectCanAddProjects,
|
||||||
selectCanFollowStudio,
|
selectCanFollowStudio,
|
||||||
selectShowCommentComposer,
|
selectShowCommentComposer,
|
||||||
selectCanDeleteAnyComment,
|
selectCanDeleteComment,
|
||||||
selectCanDeleteOwnComment,
|
|
||||||
selectCanDeleteCommentWithoutConfirm,
|
selectCanDeleteCommentWithoutConfirm,
|
||||||
selectCanReportComment,
|
selectCanReportComment,
|
||||||
selectCanRestoreComment,
|
selectCanRestoreComment,
|
||||||
|
|
|
@ -233,7 +233,7 @@ TopLevelComment.propTypes = {
|
||||||
canReply: PropTypes.bool,
|
canReply: PropTypes.bool,
|
||||||
canReport: PropTypes.bool,
|
canReport: PropTypes.bool,
|
||||||
canRestore: PropTypes.bool,
|
canRestore: PropTypes.bool,
|
||||||
commentComponent: PropTypes.element,
|
commentComponent: PropTypes.func,
|
||||||
content: PropTypes.string,
|
content: PropTypes.string,
|
||||||
datetimeCreated: PropTypes.string,
|
datetimeCreated: PropTypes.string,
|
||||||
defaultExpanded: PropTypes.bool,
|
defaultExpanded: PropTypes.bool,
|
||||||
|
|
17
src/views/studio/studio-comment.js
Normal file
17
src/views/studio/studio-comment.js
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
import {connect} from 'react-redux';
|
||||||
|
import Comment from '../preview/comment/comment.jsx';
|
||||||
|
|
||||||
|
import {
|
||||||
|
selectCanDeleteComment,
|
||||||
|
selectCanReportComment,
|
||||||
|
selectShowCommentComposer
|
||||||
|
} from '../../redux/studio-permissions';
|
||||||
|
import {selectStudioCommentsAllowed} from '../../redux/studio.js';
|
||||||
|
|
||||||
|
export default connect(
|
||||||
|
(state, ownProps) => ({
|
||||||
|
canReport: selectCanReportComment(state, ownProps.author.username),
|
||||||
|
canDelete: selectCanDeleteComment(state, ownProps.author.username),
|
||||||
|
canReply: selectShowCommentComposer(state) && selectStudioCommentsAllowed(state)
|
||||||
|
})
|
||||||
|
)(Comment);
|
|
@ -10,19 +10,17 @@ import TopLevelComment from '../preview/comment/top-level-comment.jsx';
|
||||||
import studioCommentActions from '../../redux/studio-comment-actions.js';
|
import studioCommentActions from '../../redux/studio-comment-actions.js';
|
||||||
import StudioCommentsAllowed from './studio-comments-allowed.jsx';
|
import StudioCommentsAllowed from './studio-comments-allowed.jsx';
|
||||||
import StudioCommentsNotAllowed from './studio-comments-not-allowed.jsx';
|
import StudioCommentsNotAllowed from './studio-comments-not-allowed.jsx';
|
||||||
import {selectIsAdmin, selectHasFetchedSession, selectUsername} from '../../redux/session';
|
import {selectIsAdmin, selectHasFetchedSession} from '../../redux/session';
|
||||||
import {
|
import {
|
||||||
selectShowCommentComposer,
|
selectShowCommentComposer,
|
||||||
selectCanDeleteAnyComment,
|
|
||||||
selectCanDeleteOwnComment,
|
|
||||||
selectCanDeleteCommentWithoutConfirm,
|
selectCanDeleteCommentWithoutConfirm,
|
||||||
selectCanReportComment,
|
|
||||||
selectCanRestoreComment,
|
selectCanRestoreComment,
|
||||||
selectCanEditCommentsAllowed,
|
selectCanEditCommentsAllowed,
|
||||||
selectShowCommentsList,
|
selectShowCommentsList,
|
||||||
selectShowCommentsGloballyOffError
|
selectShowCommentsGloballyOffError
|
||||||
} from '../../redux/studio-permissions';
|
} from '../../redux/studio-permissions';
|
||||||
import {selectStudioCommentsAllowed} from '../../redux/studio.js';
|
import {selectStudioCommentsAllowed} from '../../redux/studio.js';
|
||||||
|
import StudioComment from './studio-comment.js';
|
||||||
|
|
||||||
const StudioComments = ({
|
const StudioComments = ({
|
||||||
comments,
|
comments,
|
||||||
|
@ -37,12 +35,8 @@ const StudioComments = ({
|
||||||
shouldShowCommentComposer,
|
shouldShowCommentComposer,
|
||||||
shouldShowCommentsList,
|
shouldShowCommentsList,
|
||||||
shouldShowCommentsGloballyOffError,
|
shouldShowCommentsGloballyOffError,
|
||||||
username,
|
|
||||||
canDeleteAnyComment,
|
|
||||||
canDeleteOwnComment,
|
|
||||||
canDeleteCommentWithoutConfirm,
|
canDeleteCommentWithoutConfirm,
|
||||||
canEditCommentsAllowed,
|
canEditCommentsAllowed,
|
||||||
canReportComment,
|
|
||||||
canRestoreComment,
|
canRestoreComment,
|
||||||
handleDeleteComment,
|
handleDeleteComment,
|
||||||
handleRestoreComment,
|
handleRestoreComment,
|
||||||
|
@ -127,12 +121,9 @@ const StudioComments = ({
|
||||||
<TopLevelComment
|
<TopLevelComment
|
||||||
hasThreadLimit
|
hasThreadLimit
|
||||||
author={comment.author}
|
author={comment.author}
|
||||||
canDelete={canDeleteAnyComment ||
|
|
||||||
(canDeleteOwnComment && comment.author.username === username)}
|
|
||||||
canDeleteWithoutConfirm={canDeleteCommentWithoutConfirm}
|
canDeleteWithoutConfirm={canDeleteCommentWithoutConfirm}
|
||||||
canReply={shouldShowCommentComposer}
|
|
||||||
canReport={canReportComment}
|
|
||||||
canRestore={canRestoreComment}
|
canRestore={canRestoreComment}
|
||||||
|
commentComponent={StudioComment}
|
||||||
content={comment.content}
|
content={comment.content}
|
||||||
datetimeCreated={comment.datetime_created}
|
datetimeCreated={comment.datetime_created}
|
||||||
defaultExpanded={singleCommentId}
|
defaultExpanded={singleCommentId}
|
||||||
|
@ -190,12 +181,8 @@ StudioComments.propTypes = {
|
||||||
shouldShowCommentComposer: PropTypes.bool,
|
shouldShowCommentComposer: PropTypes.bool,
|
||||||
shouldShowCommentsGloballyOffError: PropTypes.bool,
|
shouldShowCommentsGloballyOffError: PropTypes.bool,
|
||||||
shouldShowCommentsList: PropTypes.bool,
|
shouldShowCommentsList: PropTypes.bool,
|
||||||
username: PropTypes.string,
|
|
||||||
canDeleteAnyComment: PropTypes.bool,
|
|
||||||
canDeleteOwnComment: PropTypes.bool,
|
|
||||||
canDeleteCommentWithoutConfirm: PropTypes.bool,
|
canDeleteCommentWithoutConfirm: PropTypes.bool,
|
||||||
canEditCommentsAllowed: PropTypes.bool,
|
canEditCommentsAllowed: PropTypes.bool,
|
||||||
canReportComment: PropTypes.bool,
|
|
||||||
canRestoreComment: PropTypes.bool,
|
canRestoreComment: PropTypes.bool,
|
||||||
handleDeleteComment: PropTypes.func,
|
handleDeleteComment: PropTypes.func,
|
||||||
handleRestoreComment: PropTypes.func,
|
handleRestoreComment: PropTypes.func,
|
||||||
|
@ -217,16 +204,12 @@ export default connect(
|
||||||
isAdmin: selectIsAdmin(state),
|
isAdmin: selectIsAdmin(state),
|
||||||
moreCommentsToLoad: state.comments.moreCommentsToLoad,
|
moreCommentsToLoad: state.comments.moreCommentsToLoad,
|
||||||
replies: state.comments.replies,
|
replies: state.comments.replies,
|
||||||
username: selectUsername(state),
|
|
||||||
commentsAllowed: selectStudioCommentsAllowed(state),
|
commentsAllowed: selectStudioCommentsAllowed(state),
|
||||||
shouldShowCommentComposer: selectShowCommentComposer(state),
|
shouldShowCommentComposer: selectShowCommentComposer(state),
|
||||||
shouldShowCommentsGloballyOffError: selectShowCommentsGloballyOffError(state),
|
shouldShowCommentsGloballyOffError: selectShowCommentsGloballyOffError(state),
|
||||||
shouldShowCommentsList: selectShowCommentsList(state),
|
shouldShowCommentsList: selectShowCommentsList(state),
|
||||||
canDeleteAnyComment: selectCanDeleteAnyComment(state),
|
|
||||||
canDeleteOwnComment: selectCanDeleteOwnComment(state),
|
|
||||||
canDeleteCommentWithoutConfirm: selectCanDeleteCommentWithoutConfirm(state),
|
canDeleteCommentWithoutConfirm: selectCanDeleteCommentWithoutConfirm(state),
|
||||||
canEditCommentsAllowed: selectCanEditCommentsAllowed(state),
|
canEditCommentsAllowed: selectCanEditCommentsAllowed(state),
|
||||||
canReportComment: selectCanReportComment(state),
|
|
||||||
canRestoreComment: selectCanRestoreComment(state),
|
canRestoreComment: selectCanRestoreComment(state),
|
||||||
postURI: `/proxy/comments/studio/${state.studio.id}`
|
postURI: `/proxy/comments/studio/${state.studio.id}`
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -1,7 +1,13 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {mountWithIntl} from '../../helpers/intl-helpers.jsx';
|
import {mountWithIntl} from '../../helpers/intl-helpers.jsx';
|
||||||
|
|
||||||
import {StudioComments} from '../../../src/views/studio/studio-comments.jsx';
|
import {StudioComments} from '../../../src/views/studio/studio-comments.jsx';
|
||||||
|
|
||||||
|
// Replace customized studio comment with default comment to avoid redux issues in the test
|
||||||
|
jest.mock('../../../src/views/studio/studio-comment.js', () => (
|
||||||
|
jest.requireActual('../../../src/views/preview/comment/comment.jsx')
|
||||||
|
));
|
||||||
|
|
||||||
describe('Studio comments', () => {
|
describe('Studio comments', () => {
|
||||||
test('if there are no comments, they get loaded', () => {
|
test('if there are no comments, they get loaded', () => {
|
||||||
const loadComments = jest.fn();
|
const loadComments = jest.fn();
|
||||||
|
|
|
@ -2,8 +2,7 @@ import {
|
||||||
selectCanEditInfo,
|
selectCanEditInfo,
|
||||||
selectCanAddProjects,
|
selectCanAddProjects,
|
||||||
selectShowCommentComposer,
|
selectShowCommentComposer,
|
||||||
selectCanDeleteAnyComment,
|
selectCanDeleteComment,
|
||||||
selectCanDeleteOwnComment,
|
|
||||||
selectCanDeleteCommentWithoutConfirm,
|
selectCanDeleteCommentWithoutConfirm,
|
||||||
selectCanReportComment,
|
selectCanReportComment,
|
||||||
selectCanRestoreComment,
|
selectCanRestoreComment,
|
||||||
|
@ -189,17 +188,22 @@ describe('studio comments', () => {
|
||||||
describe('can report comment', () => {
|
describe('can report comment', () => {
|
||||||
test.each([
|
test.each([
|
||||||
['logged in', true],
|
['logged in', true],
|
||||||
['unconfirmed', false],
|
['unconfirmed', true],
|
||||||
['logged out', false],
|
['logged out', false],
|
||||||
['muted creator', true],
|
['muted creator', true],
|
||||||
['muted logged in', true]
|
['muted logged in', true]
|
||||||
])('%s: %s', (role, expected) => {
|
])('%s: %s', (role, expected) => {
|
||||||
setStateByRole(role);
|
setStateByRole(role);
|
||||||
expect(selectCanReportComment(state)).toBe(expected);
|
expect(selectCanReportComment(state, 'not me')).toBe(expected);
|
||||||
|
});
|
||||||
|
test('cannot report your own comment', () => {
|
||||||
|
setStateByRole('logged in');
|
||||||
|
const loggedInUsername = selectUsername(state);
|
||||||
|
expect(selectCanReportComment(state, loggedInUsername)).toBe(false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('can delete any comment', () => {
|
describe('can delete others comments', () => {
|
||||||
test.each([
|
test.each([
|
||||||
['admin', true],
|
['admin', true],
|
||||||
['curator', false],
|
['curator', false],
|
||||||
|
@ -212,13 +216,13 @@ describe('studio comments', () => {
|
||||||
['muted logged in', false]
|
['muted logged in', false]
|
||||||
])('%s: %s', (role, expected) => {
|
])('%s: %s', (role, expected) => {
|
||||||
setStateByRole(role);
|
setStateByRole(role);
|
||||||
expect(selectCanDeleteAnyComment(state)).toBe(expected);
|
expect(selectCanDeleteComment(state, 'not me')).toBe(expected);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('can delete own comment', () => {
|
describe('can delete my own comment', () => {
|
||||||
test.each([
|
test.each([
|
||||||
['admin', false], // This is false here because we check for `canDeleteAnyComment` separately
|
['admin', true],
|
||||||
['curator', false],
|
['curator', false],
|
||||||
['manager', true],
|
['manager', true],
|
||||||
['creator', true],
|
['creator', true],
|
||||||
|
@ -231,7 +235,8 @@ describe('studio comments', () => {
|
||||||
['muted logged in', false]
|
['muted logged in', false]
|
||||||
])('%s: %s', (role, expected) => {
|
])('%s: %s', (role, expected) => {
|
||||||
setStateByRole(role);
|
setStateByRole(role);
|
||||||
expect(selectCanDeleteOwnComment(state)).toBe(expected);
|
const loggedInUsername = selectUsername(state);
|
||||||
|
expect(selectCanDeleteComment(state, loggedInUsername)).toBe(expected);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue