Pass a customized comment component for studios

This commit is contained in:
Paul Kaplan 2021-06-21 16:06:40 -04:00
parent fced16b08c
commit cfd52d9369
6 changed files with 49 additions and 35 deletions

View file

@ -18,14 +18,18 @@ const selectCanAddProjects = state =>
// This isn't "canComment" since they could be muted, but comment composer handles that
const selectShowCommentComposer = state => selectIsSocial(state);
const selectCanReportComment = state => selectIsSocial(state);
const selectCanReportComment = (state, commentUsername) =>
selectIsLoggedIn(state) && selectUsername(state) !== commentUsername;
const selectCanRestoreComment = state => selectIsAdmin(state);
// On the project page, project owners can delete comments with 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.
// Admins can delete comments without a confirmation.
const selectCanDeleteAnyComment = state => selectIsAdmin(state);
const selectCanDeleteOwnComment = state => isCreator(state) || isManager(state);
const selectCanDeleteComment = (state, commentUsername) => {
if (selectIsAdmin(state)) return true;
if (isManager(state) && selectUsername(state) === commentUsername) return true;
return false;
};
const selectCanDeleteCommentWithoutConfirm = state => selectIsAdmin(state);
const selectCanFollowStudio = state => selectIsLoggedIn(state);
@ -82,8 +86,7 @@ export {
selectCanAddProjects,
selectCanFollowStudio,
selectShowCommentComposer,
selectCanDeleteAnyComment,
selectCanDeleteOwnComment,
selectCanDeleteComment,
selectCanDeleteCommentWithoutConfirm,
selectCanReportComment,
selectCanRestoreComment,

View file

@ -233,7 +233,7 @@ TopLevelComment.propTypes = {
canReply: PropTypes.bool,
canReport: PropTypes.bool,
canRestore: PropTypes.bool,
commentComponent: PropTypes.element,
commentComponent: PropTypes.func,
content: PropTypes.string,
datetimeCreated: PropTypes.string,
defaultExpanded: PropTypes.bool,

View 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);

View file

@ -10,19 +10,17 @@ import TopLevelComment from '../preview/comment/top-level-comment.jsx';
import studioCommentActions from '../../redux/studio-comment-actions.js';
import StudioCommentsAllowed from './studio-comments-allowed.jsx';
import StudioCommentsNotAllowed from './studio-comments-not-allowed.jsx';
import {selectIsAdmin, selectHasFetchedSession, selectUsername} from '../../redux/session';
import {selectIsAdmin, selectHasFetchedSession} from '../../redux/session';
import {
selectShowCommentComposer,
selectCanDeleteAnyComment,
selectCanDeleteOwnComment,
selectCanDeleteCommentWithoutConfirm,
selectCanReportComment,
selectCanRestoreComment,
selectCanEditCommentsAllowed,
selectShowCommentsList,
selectShowCommentsGloballyOffError
} from '../../redux/studio-permissions';
import {selectStudioCommentsAllowed} from '../../redux/studio.js';
import StudioComment from './studio-comment.js';
const StudioComments = ({
comments,
@ -37,12 +35,8 @@ const StudioComments = ({
shouldShowCommentComposer,
shouldShowCommentsList,
shouldShowCommentsGloballyOffError,
username,
canDeleteAnyComment,
canDeleteOwnComment,
canDeleteCommentWithoutConfirm,
canEditCommentsAllowed,
canReportComment,
canRestoreComment,
handleDeleteComment,
handleRestoreComment,
@ -127,12 +121,9 @@ const StudioComments = ({
<TopLevelComment
hasThreadLimit
author={comment.author}
canDelete={canDeleteAnyComment ||
(canDeleteOwnComment && comment.author.username === username)}
canDeleteWithoutConfirm={canDeleteCommentWithoutConfirm}
canReply={shouldShowCommentComposer}
canReport={canReportComment}
canRestore={canRestoreComment}
commentComponent={StudioComment}
content={comment.content}
datetimeCreated={comment.datetime_created}
defaultExpanded={singleCommentId}
@ -190,12 +181,8 @@ StudioComments.propTypes = {
shouldShowCommentComposer: PropTypes.bool,
shouldShowCommentsGloballyOffError: PropTypes.bool,
shouldShowCommentsList: PropTypes.bool,
username: PropTypes.string,
canDeleteAnyComment: PropTypes.bool,
canDeleteOwnComment: PropTypes.bool,
canDeleteCommentWithoutConfirm: PropTypes.bool,
canEditCommentsAllowed: PropTypes.bool,
canReportComment: PropTypes.bool,
canRestoreComment: PropTypes.bool,
handleDeleteComment: PropTypes.func,
handleRestoreComment: PropTypes.func,
@ -217,16 +204,12 @@ export default connect(
isAdmin: selectIsAdmin(state),
moreCommentsToLoad: state.comments.moreCommentsToLoad,
replies: state.comments.replies,
username: selectUsername(state),
commentsAllowed: selectStudioCommentsAllowed(state),
shouldShowCommentComposer: selectShowCommentComposer(state),
shouldShowCommentsGloballyOffError: selectShowCommentsGloballyOffError(state),
shouldShowCommentsList: selectShowCommentsList(state),
canDeleteAnyComment: selectCanDeleteAnyComment(state),
canDeleteOwnComment: selectCanDeleteOwnComment(state),
canDeleteCommentWithoutConfirm: selectCanDeleteCommentWithoutConfirm(state),
canEditCommentsAllowed: selectCanEditCommentsAllowed(state),
canReportComment: selectCanReportComment(state),
canRestoreComment: selectCanRestoreComment(state),
postURI: `/proxy/comments/studio/${state.studio.id}`
}),

View file

@ -1,7 +1,13 @@
import React from 'react';
import {mountWithIntl} from '../../helpers/intl-helpers.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', () => {
test('if there are no comments, they get loaded', () => {
const loadComments = jest.fn();

View file

@ -2,8 +2,7 @@ import {
selectCanEditInfo,
selectCanAddProjects,
selectShowCommentComposer,
selectCanDeleteAnyComment,
selectCanDeleteOwnComment,
selectCanDeleteComment,
selectCanDeleteCommentWithoutConfirm,
selectCanReportComment,
selectCanRestoreComment,
@ -189,17 +188,22 @@ describe('studio comments', () => {
describe('can report comment', () => {
test.each([
['logged in', true],
['unconfirmed', false],
['unconfirmed', true],
['logged out', false],
['muted creator', true],
['muted logged in', true]
])('%s: %s', (role, expected) => {
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([
['admin', true],
['curator', false],
@ -212,13 +216,13 @@ describe('studio comments', () => {
['muted logged in', false]
])('%s: %s', (role, expected) => {
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([
['admin', false], // This is false here because we check for `canDeleteAnyComment` separately
['admin', true],
['curator', false],
['manager', true],
['creator', true],
@ -231,7 +235,8 @@ describe('studio comments', () => {
['muted logged in', false]
])('%s: %s', (role, expected) => {
setStateByRole(role);
expect(selectCanDeleteOwnComment(state)).toBe(expected);
const loggedInUsername = selectUsername(state);
expect(selectCanDeleteComment(state, loggedInUsername)).toBe(expected);
});
});