Move whether to show mute both into selectors

This commit is contained in:
seotts 2021-05-19 13:49:33 -04:00
parent 9e8186808d
commit 4f556785d3
8 changed files with 196 additions and 56 deletions

View file

@ -65,6 +65,15 @@ const selectCanRemoveProject = (state, creatorUsername, actorId) => {
return false;
};
const selectShowEditMuteError = state => selectIsMuted(state) &&
(isManager(state) || selectIsAdmin(state));
const selectShowProjectMuteError = state => selectIsMuted(state) &&
(selectIsAdmin(state) ||
isManager(state) ||
isCurator(state) ||
(selectIsSocial(state) && state.studio.openToAll));
const selectShowCuratorMuteError = state => selectIsMuted(state) && (isManager(state) || selectIsAdmin(state));
export {
selectCanEditInfo,
selectCanAddProjects,
@ -81,5 +90,8 @@ export {
selectCanRemoveCurator,
selectCanRemoveManager,
selectCanPromoteCurators,
selectCanRemoveProject
selectCanRemoveProject,
selectShowEditMuteError,
selectShowProjectMuteError,
selectShowCuratorMuteError
};

View file

@ -6,7 +6,7 @@ import classNames from 'classnames';
import {FormattedMessage} from 'react-intl';
import {selectStudioDescription, selectIsFetchingInfo} from '../../redux/studio';
import {selectCanEditInfo} from '../../redux/studio-permissions';
import {selectCanEditInfo, selectShowEditMuteError} from '../../redux/studio-permissions';
import {
Errors, mutateStudioDescription, selectIsMutatingDescription, selectDescriptionMutationError
} from '../../redux/studio-mutations';
@ -26,13 +26,13 @@ const errorToMessageId = error => {
};
const StudioDescription = ({
descriptionError, isFetching, isMutating, isMuted, description, canEditInfo, handleUpdate
descriptionError, isFetching, isMutating, isMutedEditor, description, canEditInfo, handleUpdate
}) => {
const fieldClassName = classNames('studio-description', {
'mod-fetching': isFetching,
'mod-mutating': isMutating,
'mod-form-error': !!descriptionError,
'muted': isMuted
'muted-editor': isMutedEditor
});
const [showMuteMessage, setShowMuteMessage] = useState(false);
@ -40,8 +40,8 @@ const StudioDescription = ({
return (
<div
className="studio-info-section"
onMouseEnter={() => isMuted && setShowMuteMessage(true)}
onMouseLeave={() => isMuted && setShowMuteMessage(false)}
onMouseEnter={() => isMutedEditor && setShowMuteMessage(true)}
onMouseLeave={() => isMutedEditor && setShowMuteMessage(false)}
>
{canEditInfo ? (
<React.Fragment>
@ -77,7 +77,7 @@ StudioDescription.propTypes = {
canEditInfo: PropTypes.bool,
isFetching: PropTypes.bool,
isMutating: PropTypes.bool,
isMuted: PropTypes.bool,
isMutedEditor: PropTypes.bool,
description: PropTypes.string,
handleUpdate: PropTypes.func
};
@ -88,7 +88,7 @@ export default connect(
canEditInfo: selectCanEditInfo(state),
isFetching: selectIsFetchingInfo(state),
isMutating: selectIsMutatingDescription(state),
isMuted: selectIsMuted(state),
isMutedEditor: selectShowEditMuteError(state),
descriptionError: selectDescriptionMutationError(state)
}),
{

View file

@ -6,7 +6,7 @@ import classNames from 'classnames';
import {FormattedMessage} from 'react-intl';
import {selectStudioImage, selectIsFetchingInfo} from '../../redux/studio';
import {selectCanEditInfo} from '../../redux/studio-permissions';
import {selectCanEditInfo, selectShowEditMuteError} from '../../redux/studio-permissions';
import {
Errors, mutateStudioImage, selectIsMutatingImage, selectImageMutationError
} from '../../redux/studio-mutations';
@ -26,13 +26,13 @@ const errorToMessageId = error => {
const blankImage = 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==';
const StudioImage = ({
imageError, isFetching, isMutating, isMuted, image, canEditInfo, handleUpdate
imageError, isFetching, isMutating, isMutedEditor, image, canEditInfo, handleUpdate
}) => {
const [uploadPreview, setUploadPreview] = React.useState(null);
const fieldClassName = classNames('studio-info-section', {
'mod-fetching': isFetching,
'mod-mutating': isMutating,
'muted': isMuted
'muted': isMutedEditor
});
let src = image || blankImage;
if (uploadPreview && !imageError) src = uploadPreview;
@ -41,17 +41,17 @@ const StudioImage = ({
return (
<div
className={fieldClassName}
onMouseEnter={() => isMuted && setShowMuteMessage(true)}
onMouseLeave={() => isMuted && setShowMuteMessage(false)}
onMouseEnter={() => isMutedEditor && setShowMuteMessage(true)}
onMouseLeave={() => isMutedEditor && setShowMuteMessage(false)}
>
<img
className="studio-image"
src={src}
/>
{canEditInfo && !isFetching &&
{(isMutedEditor || canEditInfo) && !isFetching &&
<React.Fragment>
<input
disabled={isMutating}
disabled={isMutating || !canEditInfo}
type="file"
accept="image/*"
onChange={e => {
@ -76,7 +76,7 @@ StudioImage.propTypes = {
canEditInfo: PropTypes.bool,
isFetching: PropTypes.bool,
isMutating: PropTypes.bool,
isMuted: PropTypes.bool,
isMutedEditor: PropTypes.bool,
image: PropTypes.string,
handleUpdate: PropTypes.func
};
@ -87,7 +87,7 @@ export default connect(
canEditInfo: selectCanEditInfo(state),
isFetching: selectIsFetchingInfo(state),
isMutating: selectIsMutatingImage(state),
isMuted: selectIsMuted(state),
isMutedEditor: selectShowEditMuteError(state),
imageError: selectImageMutationError(state)
}),
{

View file

@ -5,7 +5,7 @@ import StudioOpenToAll from './studio-open-to-all.jsx';
import {FormattedMessage} from 'react-intl';
import {projects} from './lib/redux-modules';
import {selectCanAddProjects, selectCanEditOpenToAll} from '../../redux/studio-permissions';
import {selectCanAddProjects, selectCanEditOpenToAll, selectHasProjectPermissions, selectShowProjectMuteError} from '../../redux/studio-permissions';
import Debug from './debug.jsx';
import StudioProjectAdder from './studio-project-adder.jsx';
import StudioProjectTile from './studio-project-tile.jsx';
@ -16,7 +16,7 @@ import {selectMuteStatus} from '../../redux/session.js';
import {formatRelativeTime} from '../../lib/format-time.js';
const StudioProjects = ({
canAddProjects, canEditOpenToAll, items, error, loading, moreToLoad, onLoadMore, muteExpiresAtMs
canAddProjects, canEditOpenToAll, hasPermission, items, error, loading, moreToLoad, onLoadMore, muteExpiresAtMs, showMuteError
}) => {
useEffect(() => {
if (items.length === 0) onLoadMore();
@ -28,7 +28,7 @@ const StudioProjects = ({
<h2><FormattedMessage id="studio.projectsHeader" /></h2>
{canEditOpenToAll && <StudioOpenToAll />}
</div>
{muteExpiresAtMs > Date.now() &&
{showMuteError &&
<CommentingStatus>
<p>
<FormattedMessage
@ -125,7 +125,8 @@ StudioProjects.propTypes = {
error: PropTypes.object, // eslint-disable-line react/forbid-prop-types
moreToLoad: PropTypes.bool,
muteExpiresAtMs: PropTypes.number,
onLoadMore: PropTypes.func
onLoadMore: PropTypes.func,
showMuteError: PropTypes.bool
};
export default connect(
@ -133,6 +134,7 @@ export default connect(
...projects.selector(state),
canAddProjects: selectCanAddProjects(state),
canEditOpenToAll: selectCanEditOpenToAll(state),
showMuteError: selectShowProjectMuteError(state),
muteExpiresAtMs: (selectMuteStatus(state).muteExpiresAt * 1000 || 0)
}),
{

View file

@ -6,7 +6,7 @@ import classNames from 'classnames';
import {FormattedMessage} from 'react-intl';
import {selectStudioTitle, selectIsFetchingInfo} from '../../redux/studio';
import {selectCanEditInfo} from '../../redux/studio-permissions';
import {selectCanEditInfo, selectShowEditMuteError} from '../../redux/studio-permissions';
import {Errors, mutateStudioTitle, selectIsMutatingTitle, selectTitleMutationError} from '../../redux/studio-mutations';
import ValidationMessage from '../../components/forms/validation-message.jsx';
import {selectIsMuted} from '../../redux/session';
@ -22,13 +22,13 @@ const errorToMessageId = error => {
};
const StudioTitle = ({
titleError, isFetching, isMutating, isMuted, title, canEditInfo, handleUpdate
titleError, isFetching, isMutating, isMutedEditor, title, canEditInfo, handleUpdate
}) => {
const fieldClassName = classNames('studio-title', {
'mod-fetching': isFetching,
'mod-mutating': isMutating,
'mod-form-error': !!titleError,
'muted': isMuted
'muted-editor': isMutedEditor
});
const [showMuteMessage, setShowMuteMessage] = useState(false);
@ -36,8 +36,8 @@ const StudioTitle = ({
return (
<div
className="studio-info-section"
onMouseEnter={() => isMuted && setShowMuteMessage(true)}
onMouseLeave={() => isMuted && setShowMuteMessage(false)}
onMouseEnter={() => isMutedEditor && setShowMuteMessage(true)}
onMouseLeave={() => isMutedEditor && setShowMuteMessage(false)}
>
{canEditInfo ? (
<React.Fragment>
@ -67,7 +67,7 @@ StudioTitle.propTypes = {
canEditInfo: PropTypes.bool,
isFetching: PropTypes.bool,
isMutating: PropTypes.bool,
isMuted: PropTypes.bool,
isMutedEditor: PropTypes.bool,
title: PropTypes.string,
handleUpdate: PropTypes.func
};
@ -78,7 +78,7 @@ export default connect(
canEditInfo: selectCanEditInfo(state),
isFetching: selectIsFetchingInfo(state),
isMutating: selectIsMutatingTitle(state),
isMuted: selectIsMuted(state),
isMutedEditor: selectShowEditMuteError(state),
titleError: selectTitleMutationError(state)
}),
{

View file

@ -42,8 +42,9 @@ import {selectIsMuted, selectMuteStatus} from '../../redux/session.js';
import {formatRelativeTime} from '../../lib/format-time.js';
import CommentingStatus from '../../components/commenting-status/commenting-status.jsx';
import {FormattedMessage} from 'react-intl';
import { selectHasCuratorEditPermissions, selectShowCuratorMuteError } from '../../redux/studio-permissions.js';
const StudioShell = ({isMuted, muteExpiresAtMs, studioLoadFailed}) => {
const StudioShell = ({showCuratorMuteBox, muteExpiresAtMs, studioLoadFailed}) => {
const match = useRouteMatch();
return (
@ -58,7 +59,7 @@ const StudioShell = ({isMuted, muteExpiresAtMs, studioLoadFailed}) => {
<div>
<Switch>
<Route path={`${match.path}/curators`}>
{isMuted &&
{showCuratorMuteBox &&
<CommentingStatus className="studio-curator-mute-box">
<p>
<FormattedMessage
@ -95,14 +96,14 @@ const StudioShell = ({isMuted, muteExpiresAtMs, studioLoadFailed}) => {
};
StudioShell.propTypes = {
isMuted: PropTypes.bool,
showCuratorMuteBox: PropTypes.bool,
muteExpiresAtMs: PropTypes.number,
studioLoadFailed: PropTypes.bool
};
const ConnectedStudioShell = connect(
state => ({
isMuted: selectIsMuted(state),
showCuratorMuteBox: selectShowCuratorMuteError(state),
studioLoadFailed: selectStudioLoadFailed(state),
muteExpiresAtMs: (selectMuteStatus(state).muteExpiresAt * 1000 || 0)
}),

View file

@ -51,12 +51,11 @@
}
}
},
"isMuted": {
"user1Muted": {
"session": {
"user": {
"id": 1,
"username": "user1-username",
"token": "user1-token"
"username": "user1-username"
},
"permissions": {
"mute_status": {"muteExpiresAt": 32515480478, "offenses": [], "showWarning": false},

View file

@ -14,7 +14,10 @@ import {
selectCanRemoveCurator,
selectCanRemoveManager,
selectCanPromoteCurators,
selectCanRemoveProject
selectCanRemoveProject,
selectShowProjectMuteError,
selectShowCuratorMuteError,
selectShowEditMuteError
} from '../../../src/redux/studio-permissions';
import {getInitialState as getInitialStudioState} from '../../../src/redux/studio';
@ -39,6 +42,7 @@ const setStateByRole = (role) => {
case 'creator':
state.studio = studios.creator1;
state.session = sessions.user1Social;
debugger;
break;
case 'logged in':
state.session = sessions.user1Social;
@ -51,8 +55,21 @@ const setStateByRole = (role) => {
case 'invited':
state.studio = studios.isInvited;
break;
case 'muted':
state.session = sessions.isMuted;
case 'muted creator':
state.studio = studios.creator1;
state.session = sessions.user1Muted;
debugger;
break;
case 'muted manager':
state.studio = studios.isManager;
state.session = sessions.user1Muted;
break;
case 'muted curator':
state.studio = studios.isCurator;
state.session = sessions.user1Muted;
break;
case 'muted logged in':
state.session = sessions.user1Muted;
break;
default:
throw new Error('Unknown user role in test: ' + role);
@ -76,7 +93,8 @@ describe('studio info', () => {
['logged in', false],
['unconfirmed', false],
['logged out', false],
['muted', false]
['muted creator', false],
['muted logged in', false]
])('%s: %s', (role, expected) => {
setStateByRole(role);
expect(selectCanEditInfo(state)).toBe(expected);
@ -94,7 +112,8 @@ describe('studio projects', () => {
['logged in', false],
['unconfirmed', false],
['logged out', false],
['muted', false]
['muted creator', false],
['muted logged in', false]
])('%s: %s', (role, expected) => {
setStateByRole(role);
expect(selectCanAddProjects(state)).toBe(expected);
@ -106,7 +125,8 @@ describe('studio projects', () => {
['logged in', true],
['unconfirmed', false],
['logged out', false],
['muted', false]
['muted creator', false],
['muted logged in', false]
])('%s: %s', (role, expected) => {
setStateByRole(role);
state.studio.openToAll = true;
@ -123,7 +143,8 @@ describe('studio projects', () => {
['logged in', false], // false for projects that are not theirs, see below
['unconfirmed', false],
['logged out', false],
['muted', false]
['muted creator', false],
['muted logged in', false]
])('%s: %s', (role, expected) => {
setStateByRole(role);
expect(selectCanRemoveProject(state, 'not-me', 'not-me')).toBe(expected);
@ -155,7 +176,8 @@ describe('studio comments', () => {
['logged in', true],
['unconfirmed', false],
['logged out', false],
['muted', true] // comment composer is there, but contains muted ComposeStatus
['muted creator', true], // comment composer is there, but contains muted ComposeStatus
['muted logged in', true]
])('%s: %s', (role, expected) => {
setStateByRole(role);
expect(selectShowCommentComposer(state)).toBe(expected);
@ -167,7 +189,8 @@ describe('studio comments', () => {
['logged in', true],
['unconfirmed', false],
['logged out', false],
['muted', true]
['muted creator', true],
['muted logged in', true]
])('%s: %s', (role, expected) => {
setStateByRole(role);
expect(selectCanReportComment(state)).toBe(expected);
@ -183,7 +206,8 @@ describe('studio comments', () => {
['logged in', false],
['unconfirmed', false],
['logged out', false],
['muted', false]
['muted creator', false],
['muted logged in', false]
])('%s: %s', (role, expected) => {
setStateByRole(role);
expect(selectCanDeleteComment(state)).toBe(expected);
@ -199,7 +223,8 @@ describe('studio comments', () => {
['logged in', false],
['unconfirmed', false],
['logged out', false],
['muted', false]
['muted creator', false],
['muted logged in', false]
])('%s: %s', (role, expected) => {
setStateByRole(role);
expect(selectCanDeleteCommentWithoutConfirm(state)).toBe(expected);
@ -215,7 +240,8 @@ describe('studio comments', () => {
['logged in', false],
['unconfirmed', false],
['logged out', false],
['muted', false]
['muted creator', false],
['muted logged in', false]
])('%s: %s', (role, expected) => {
setStateByRole(role);
expect(selectCanRestoreComment(state)).toBe(expected);
@ -227,7 +253,8 @@ describe('studio comments', () => {
['logged in', true],
['unconfirmed', true],
['logged out', false],
['muted', true]
['muted creator', true],
['muted logged in', true]
])('%s: %s', (role, expected) => {
setStateByRole(role);
expect(selectCanFollowStudio(state)).toBe(expected);
@ -243,7 +270,8 @@ describe('studio comments', () => {
['logged in', false],
['unconfirmed', false],
['logged out', false],
['muted', false]
['muted creator', false],
['muted logged in', false]
])('%s: %s', (role, expected) => {
setStateByRole(role);
expect(selectCanEditCommentsAllowed(state)).toBe(expected);
@ -259,7 +287,8 @@ describe('studio comments', () => {
['logged in', false],
['unconfirmed', false],
['logged out', false],
['muted', false]
['muted creator', false],
['muted logged in', false]
])('%s: %s', (role, expected) => {
setStateByRole(role);
expect(selectCanEditOpenToAll(state)).toBe(expected);
@ -278,7 +307,8 @@ describe('studio members', () => {
['logged in', false],
['unconfirmed', false],
['logged out', false],
['muted', false]
['muted creator', false],
['muted logged in', false]
])('%s: %s', (role, expected) => {
setStateByRole(role);
expect(selectShowCuratorInvite(state)).toBe(expected);
@ -294,7 +324,8 @@ describe('studio members', () => {
['logged in', false],
['unconfirmed', false],
['logged out', false],
['muted', false]
['muted creator', false],
['muted logged in', false]
])('%s: %s', (role, expected) => {
setStateByRole(role);
expect(selectCanPromoteCurators(state)).toBe(expected);
@ -310,7 +341,8 @@ describe('studio members', () => {
['logged in', false],
['unconfirmed', false],
['logged out', false],
['muted', false]
['muted creator', false],
['muted logged in', false]
])('%s: %s', (role, expected) => {
setStateByRole(role);
expect(selectCanRemoveCurator(state, 'others-username')).toBe(expected);
@ -332,7 +364,8 @@ describe('studio members', () => {
['logged in', false],
['unconfirmed', false],
['logged out', false],
['muted', false]
['muted creator', false],
['muted logged in', false]
])('%s: %s', (role, expected) => {
setStateByRole(role);
expect(selectCanRemoveManager(state, '123')).toBe(expected);
@ -347,7 +380,8 @@ describe('studio members', () => {
['logged in', false],
['unconfirmed', false],
['logged out', false],
['muted', false]
['muted creator', false],
['muted logged in', false]
])('%s: %s', (role, expected) => {
setStateByRole(role);
state.studio.owner = 'the creator';
@ -365,10 +399,102 @@ describe('studio members', () => {
['logged in', false],
['unconfirmed', false],
['logged out', false],
['muted', false]
['muted creator', false],
['muted logged in', false]
])('%s: %s', (role, expected) => {
setStateByRole(role);
expect(selectCanInviteCurators(state)).toBe(expected);
});
});
});
describe('studio mute errors', () => {
describe('should show projects mute error', () => {
test.each([
['admin', false],
['curator', false],
['manager', false],
['creator', false],
['logged in', false],
['unconfirmed', false],
['logged out', false],
['muted creator', true],
['muted manager', true],
['muted curator', true],
['muted logged in', false]
])('%s: %s', (role, expected) => {
setStateByRole(role);
expect(selectShowProjectMuteError(state)).toBe(expected);
});
});
describe('should show projects mute error, open to all', () => {
test.each([
['admin', false],
['curator', false],
['manager', false],
['creator', false],
['logged in', false],
['unconfirmed', false],
['logged out', false],
['muted creator', true],
['muted manager', true],
['muted curator', true],
['muted logged in', true]
])('%s: %s', (role, expected) => {
setStateByRole(role);
state.studio.openToAll = true;
expect(selectShowProjectMuteError(state)).toBe(expected);
});
});
describe('should show curators mute error', () => {
test.each([
['admin', false],
['curator', false],
['manager', false],
['creator', false],
['logged in', false],
['unconfirmed', false],
['logged out', false],
['muted creator', true],
['muted manager', true],
['muted curator', false],
['muted logged in', false]
])('%s: %s', (role, expected) => {
setStateByRole(role);
expect(selectShowCuratorMuteError(state)).toBe(expected);
});
});
describe('should show edit info mute error', () => {
test.each([
['admin', false],
['curator', false],
['manager', false],
['creator', false],
['logged in', false],
['unconfirmed', false],
['logged out', false],
['muted creator', true],
['muted manager', true],
['muted curator', false],
['muted logged in', false]
])('%s: %s', (role, expected) => {
setStateByRole(role);
expect(selectShowEditMuteError(state)).toBe(expected);
});
});
describe('should show edit info mute error, muted creator', () => {
test('', () => {
// const state = {
// session: getInitialSessionState(),
// studio: getInitialStudioState()
// };
setStateByRole('muted creator');
expect(selectShowEditMuteError(state)).toBe(true);
});
});
});