diff --git a/packages/component-faraday-selectors/src/index.js b/packages/component-faraday-selectors/src/index.js index 4f258fa4436f16ae850c98ba02d1b201cd61e634..fab299296f67b3f089781024a0c9a37c4dd7ed81 100644 --- a/packages/component-faraday-selectors/src/index.js +++ b/packages/component-faraday-selectors/src/index.js @@ -66,6 +66,7 @@ const canHeViewEditorialCommentsStatuses = [ 'rejected', 'accepted', 'inQA', + 'pendingApproval', ] export const canHeViewEditorialComments = (state, collection = {}) => { const isHE = isHEToManuscript(state, collection.id) diff --git a/packages/component-faraday-ui/src/manuscriptDetails/ManuscriptEicDecision.js b/packages/component-faraday-ui/src/manuscriptDetails/ManuscriptEicDecision.js index a6f66d3736b655bb1835539cd73115feac761ceb..1c40f7107e6358774fcac738b4e62cb0774b16a4 100644 --- a/packages/component-faraday-ui/src/manuscriptDetails/ManuscriptEicDecision.js +++ b/packages/component-faraday-ui/src/manuscriptDetails/ManuscriptEicDecision.js @@ -1,6 +1,6 @@ import React from 'react' -import { get } from 'lodash' -import { compose } from 'recompose' +import { get, last } from 'lodash' +import { compose, withProps } from 'recompose' import styled from 'styled-components' import { reduxForm } from 'redux-form' import { th } from '@pubsweet/ui-toolkit' @@ -19,12 +19,34 @@ import { withFetching, } from '../' +const eicDecisions = [ + { + value: 'return-to-handling-editor', + label: 'Return to Handling Editor', + modalTitle: 'Return Manuscript', + modalSubtitle: + 'A returning manuscript to Handling Editor decision is final', + }, + { + value: 'publish', + label: 'Publish', + modalTitle: 'Publish Manuscript', + modalSubtitle: 'A publish decision is final', + }, + { + value: 'reject', + label: 'Reject', + modalTitle: 'Reject Manuscript', + modalSubtitle: 'A rejection decision is final', + }, +] + const ManuscriptEicDecision = ({ isFetching, formValues, handleSubmit, messagesLabel, - options = [], + collection = {}, ...rest }) => ( <ContextualBox label="Your Editorial Decision" {...rest}> @@ -33,29 +55,36 @@ const ManuscriptEicDecision = ({ <ItemOverrideAlert flex={0} vertical> <Label required>Decision</Label> <ValidatedField - component={input => <Menu {...input} options={options} />} + component={input => ( + <Menu + {...input} + options={ + get(collection, 'status', 'submitted') === 'submitted' + ? [last(eicDecisions)] + : eicDecisions + } + /> + )} name="decision" validate={[required]} /> </ItemOverrideAlert> </Row> - <Row mt={2}> - <Item vertical> - <Label required> - { - messagesLabel[ - get(formValues, 'decision', 'return-to-handling-editor') - ] - } - </Label> - <ValidatedField - component={ValidatedTextArea} - name="message" - validate={[required]} - /> - </Item> - </Row> + {get(formValues, 'decision') !== 'publish' && ( + <Row mt={2}> + <Item vertical> + <Label required> + {messagesLabel[get(formValues, 'decision', 'reject')]} + </Label> + <ValidatedField + component={ValidatedTextArea} + name="message" + validate={[required]} + /> + </Item> + </Row> + )} <Row justify="flex-end" mt={4}> <Button onClick={handleSubmit} primary size="medium"> @@ -73,15 +102,32 @@ export default compose( modalKey: 'eic-decision', modalComponent: MultiAction, })), + withProps(({ formValues }) => ({ + modalTitle: eicDecisions.find( + o => o.value === get(formValues, 'decision', 'publish'), + ).modalTitle, + modalSubtitle: eicDecisions.find( + o => o.value === get(formValues, 'decision', 'publish'), + ).modalSubtitle, + })), reduxForm({ form: 'eic-decision', onSubmit: ( values, dispatch, - { submitDecision, showModal, setFetching }, + { + submitDecision, + showModal, + setFetching, + modalTitle, + confirmMessage, + modalSubtitle, + }, ) => { showModal({ - title: 'Are you sure you want to submit this decision?', + title: `${modalTitle}?`, + confirmText: modalTitle, + subtitle: modalSubtitle, onConfirm: modalProps => { submitDecision(values, { ...modalProps, setFetching }) }, diff --git a/packages/component-faraday-ui/src/modals/MultiAction.js b/packages/component-faraday-ui/src/modals/MultiAction.js index f63a776a7458f679e39440c7870c698e74d0f31a..f441ad6ec0ac2d61aaa4fa968ac4d7648ef26d38 100644 --- a/packages/component-faraday-ui/src/modals/MultiAction.js +++ b/packages/component-faraday-ui/src/modals/MultiAction.js @@ -20,7 +20,11 @@ const MultiAction = ({ <Root> <IconButton icon="x" onClick={onClose} right={5} secondary top={5} /> <H2>{title}</H2> - {subtitle && <Text secondary>{subtitle}</Text>} + {subtitle && ( + <Text mb={1} secondary> + {subtitle} + </Text> + )} {renderContent()} {modalError && ( <Text align="center" error mt={1}> diff --git a/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/notifications/notifications.js b/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/notifications/notifications.js index eee5ba2fc9ee4eb1206172c29b7d6c298dfeeabd..9bb9c3a6cbd7d7b66222cb4b472e108c08304a06 100644 --- a/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/notifications/notifications.js +++ b/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/notifications/notifications.js @@ -60,7 +60,11 @@ module.exports = { // the EiC recommends to publish so an email to the EQA needs to be sent, // one requesting approval or one informing them that the manuscript has been published - if (isEditorInChief && recommendation === 'publish') { + if ( + isEditorInChief && + recommendation === 'publish' && + collection.technicalChecks.token + ) { sendEQAEmail({ email, eicName, @@ -77,7 +81,6 @@ module.exports = { // send HE emails when a review is submitted // or when the EiC makes a recommendation after peer review - if ( recommendationType === 'review' || (isEditorInChief && diff --git a/packages/component-manuscript-manager/src/routes/technicalChecks/notifications/notifications.js b/packages/component-manuscript-manager/src/routes/technicalChecks/notifications/notifications.js index 631f6719315bd164636fdb88b9632caa4c08d15a..8380da030638ce5c7d66293fd7531ac01841a237 100644 --- a/packages/component-manuscript-manager/src/routes/technicalChecks/notifications/notifications.js +++ b/packages/component-manuscript-manager/src/routes/technicalChecks/notifications/notifications.js @@ -1,5 +1,4 @@ const config = require('config') -const { get } = require('lodash') const Email = require('@pubsweet/component-email-templating') const { @@ -9,12 +8,10 @@ const { } = require('pubsweet-component-helper-service') const { getEmailCopy } = require('./emailCopy') -const unsubscribeSlug = config.get('unsubscribe.url') const { name: journalName, staffEmail } = config.get('journal') module.exports = { async sendNotifications({ - isEQA, agree, baseUrl, collection, @@ -28,10 +25,7 @@ module.exports = { handlingEditor: collection.handlingEditor, }) - const { - activeAuthors: authors, - submittingAuthor, - } = await fragmentHelper.getAuthorData({ + const { submittingAuthor } = await fragmentHelper.getAuthorData({ UserModel, }) @@ -60,42 +54,14 @@ module.exports = { }, }) - if (agree && isEQA) { - email.content.signatureName = await userHelper.getEiCName() - - sendHandlingEditorEmail({ - email, - baseUrl, - titleText, - subjectBaseText, - handlingEditor: get(collection, 'handlingEditor', {}), - }) - sendSubmittedReviewersEmail({ - email, - baseUrl, - titleText, - UserModel, - fragmentHelper, - subjectBaseText, - }) - - sendAuthorsEmail({ - email, - baseUrl, - titleText, - subjectBaseText, - fragmentAuthors: authors, - }) - } else { - sendEditorsEmail({ - email, - agree, - customId, - comments, - titleText, - userHelper, - }) - } + sendEditorsEmail({ + email, + agree, + customId, + comments, + titleText, + userHelper, + }) }, } @@ -137,113 +103,3 @@ const sendEditorsEmail = async ({ email.sendEmail({ html, text }) }) } - -const sendHandlingEditorEmail = ({ - email, - baseUrl, - titleText, - handlingEditor, - subjectBaseText, -}) => { - email.content.subject = `${subjectBaseText} Decision` - const emailType = 'he-manuscript-published' - - email.toUser = { - email: handlingEditor.email, - name: handlingEditor.name, - } - email.content.unsubscribeLink = services.createUrl(baseUrl, unsubscribeSlug, { - id: handlingEditor.id, - }) - - const { html, text } = email.getNotificationBody({ - emailBodyProps: getEmailCopy({ - emailType, - titleText, - }), - }) - email.sendEmail({ html, text }) -} - -const sendSubmittedReviewersEmail = async ({ - email, - baseUrl, - titleText, - UserModel, - fragmentHelper, - subjectBaseText, -}) => { - email.content.subject = `${subjectBaseText} Decision` - - const reviewers = (await fragmentHelper.getReviewers({ - UserModel, - type: 'submitted', - })).map(rev => ({ - ...rev, - ...getEmailCopy({ - emailType: 'submitted-reviewers-after-publish', - titleText, - }), - })) - - reviewers.forEach(reviewer => { - email.toUser = { - email: reviewer.email, - name: `${reviewer.firstName} ${reviewer.lastName}`, - } - email.content.unsubscribeLink = services.createUrl( - baseUrl, - unsubscribeSlug, - { - id: reviewer.id, - }, - ) - const { html, text } = email.getNotificationBody({ - emailBodyProps: { - paragraph: reviewer.paragraph, - hasLink: reviewer.hasLink, - }, - }) - email.sendEmail({ html, text }) - }) -} - -const sendAuthorsEmail = ({ - email, - baseUrl, - titleText, - subjectBaseText, - fragmentAuthors, -}) => { - const emailType = 'author-manuscript-published' - email.content.subject = `${subjectBaseText} Published` - - const authors = fragmentAuthors.map(author => ({ - ...author, - ...getEmailCopy({ - emailType, - titleText, - }), - })) - - authors.forEach(author => { - email.toUser = { - email: author.email, - name: `${author.firstName} ${author.lastName}`, - } - email.content.unsubscribeLink = services.createUrl( - baseUrl, - unsubscribeSlug, - { - id: author.id, - }, - ) - const { html, text } = email.getNotificationBody({ - emailBodyProps: { - paragraph: author.paragraph, - hasLink: author.hasLink, - }, - }) - email.sendEmail({ html, text }) - }) -} diff --git a/packages/component-manuscript-manager/src/routes/technicalChecks/patch.js b/packages/component-manuscript-manager/src/routes/technicalChecks/patch.js index 4afb91c9d628e6a13e19bfea7d2360527dab8ab5..fcb8a59daf70b1bc7129fa23b1fe664d8de5750e 100644 --- a/packages/component-manuscript-manager/src/routes/technicalChecks/patch.js +++ b/packages/component-manuscript-manager/src/routes/technicalChecks/patch.js @@ -1,7 +1,13 @@ -const { get, find, isEmpty } = require('lodash') +const { get, find, isEmpty, last } = require('lodash') const { services } = require('pubsweet-component-helper-service') -const { sendNotifications } = require('./notifications/notifications') +const { + sendNotifications: sendEQSNotifications, +} = require('./notifications/notifications') + +const { + sendNotifications: sendEQANotifications, +} = require('../fragmentsRecommendations/notifications/notifications') const TECHNICAL_STEPS = { EQS: 'eqs', @@ -64,15 +70,33 @@ module.exports = ({ Collection, Fragment, User }) => async (req, res) => { collection.status = setNewStatus(step, agree) await collection.save() - sendNotifications({ - User, - agree, - comments, - Fragment, - collection, - baseUrl: services.getBaseUrl(req), - isEQA: step === TECHNICAL_STEPS.EQA, - }) + const isEQA = get(collection, 'technicalChecks.eqa', false) + const baseUrl = services.getBaseUrl(req) + if (isEQA) { + const fragment = await Fragment.find(last(collection.fragments)) + + sendEQANotifications({ + baseUrl, + fragment, + collection, + hasEQA: true, + UserModel: User, + isEditorInChief: true, + newRecommendation: { + recommendation: 'publish', + recommendationType: 'editorRecommendation', + }, + }) + } else { + sendEQSNotifications({ + User, + agree, + comments, + Fragment, + collection, + baseUrl, + }) + } return res.status(200).json(collection) } catch (e) { diff --git a/packages/component-manuscript/src/components/EditorialCommentCard.js b/packages/component-manuscript/src/components/EditorialCommentCard.js index 077073dbe235136c41641f1aac1a72656b929a88..366200e4fba723bc2c2a7431b4d19b39ea0501b9 100644 --- a/packages/component-manuscript/src/components/EditorialCommentCard.js +++ b/packages/component-manuscript/src/components/EditorialCommentCard.js @@ -6,8 +6,14 @@ import { withFileDownload, } from 'pubsweet-component-faraday-ui' -const EditorialCommentCard = ({ journal, reports = [] }) => ( - <ContextualBox label="Editorial Comments" mb={2}> +const EditorialCommentCard = ({ journal, reports = [], toggle, expanded }) => ( + <ContextualBox + expanded={expanded} + label="Editorial Comments" + mb={2} + scrollIntoView + toggle={toggle} + > {reports.map(report => ( <EditorialReportCard journal={journal} diff --git a/packages/component-manuscript/src/components/ManuscriptLayout.js b/packages/component-manuscript/src/components/ManuscriptLayout.js index b054b71e438ae82970fbfbfe8680a231e5e8782e..6c1cfc840e633a7eb86a685e7b0f7f2316eae15c 100644 --- a/packages/component-manuscript/src/components/ManuscriptLayout.js +++ b/packages/component-manuscript/src/components/ManuscriptLayout.js @@ -1,6 +1,6 @@ import React, { Fragment } from 'react' import styled from 'styled-components' -import { isEmpty, get, last } from 'lodash' +import { isEmpty, get } from 'lodash' import { Text, paddingHelper, @@ -18,15 +18,8 @@ import ReviewerReportCard from './ReviewReportCard' import ReviewerReportForm from './ReviewerReportForm' import EditorialCommentCard from './EditorialCommentCard' -const eicDecisions = [ - { value: 'return-to-handling-editor', label: 'Return to Handling Editor' }, - { value: 'publish', label: 'Publish' }, - { value: 'reject', label: 'Reject' }, -] - const messagesLabel = { 'return-to-handling-editor': 'Comments for Handling Editor', - publish: 'Comments for Author', reject: 'Comments for Author', } @@ -70,6 +63,8 @@ const ManuscriptLayout = ({ reviewerRecommendations, toggleReviewerDetails, reviewerDetailsExpanded, + toggleHeRecommendation, + heRecommendationExpanded, onInvitePublonReviewer, }) => ( <Root pb={30}> @@ -104,8 +99,10 @@ const ManuscriptLayout = ({ {get(currentUser, 'permissions.canViewEditorialComments', true) && ( <EditorialCommentCard + expanded={heRecommendationExpanded} journal={journal} reports={editorialRecommendations} + toggle={toggleHeRecommendation} /> )} @@ -200,14 +197,11 @@ const ManuscriptLayout = ({ {get(currentUser, 'permissions.canMakeDecision', false) && ( <ManuscriptEicDecision + collection={collection} formValues={get(formValues, 'eicDecision')} + highlight={editorialRecommendations.length > 0} messagesLabel={messagesLabel} mt={2} - options={ - get(collection, 'status', 'submitted') === 'submitted' - ? [last(eicDecisions)] - : eicDecisions - } submitDecision={createRecommendation} /> )} diff --git a/packages/component-manuscript/src/components/ManuscriptPage.js b/packages/component-manuscript/src/components/ManuscriptPage.js index 1ed05f930396ebf4f38f6ccafec63e9661f885c3..912cab3e23ec4fe707dffe55fe8e41b96d755d9f 100644 --- a/packages/component-manuscript/src/components/ManuscriptPage.js +++ b/packages/component-manuscript/src/components/ManuscriptPage.js @@ -487,6 +487,10 @@ export default compose( toggleReviewerDetails: toggle, reviewerDetailsExpanded: expanded, })), + fromRenderProps(RemoteOpener, ({ toggle, expanded }) => ({ + toggleHeRecommendation: toggle, + heRecommendationExpanded: expanded, + })), withProps(({ currentUser, collection, submittedOwnRecommendation }) => ({ getSignedUrl, shouldReview: @@ -507,10 +511,12 @@ export default compose( getPublonsReviewers, hasManuscriptFailure, fetchUpdatedCollection, + editorialRecommendations, currentUser: { isInvitedHE, isInvitedToReview, isHEToManuscript, + isEIC, permissions: { canInviteReviewers }, }, } = this.props @@ -553,6 +559,10 @@ export default compose( if (isHEToManuscript && !!reviewerReports.length) { this.props.toggleReviewerDetails() } + + if (isEIC && !!editorialRecommendations.length) { + this.props.toggleHeRecommendation() + } }, }), )(ManuscriptLayout) diff --git a/packages/components-faraday/src/components/MakeDecision/DecisionForm.js b/packages/components-faraday/src/components/MakeDecision/DecisionForm.js index 3fab58f21c15bcdd312cc0fa0f8df64ef928350e..b698cf1f41d8b9c2fac0ba97fa7b01f588eac0ce 100644 --- a/packages/components-faraday/src/components/MakeDecision/DecisionForm.js +++ b/packages/components-faraday/src/components/MakeDecision/DecisionForm.js @@ -73,7 +73,7 @@ const DecisionForm = ({ {decision === 'return-to-handling-editor' && ( <Row> <RowItem vertical> - <Label>Comments for Handling Editor</Label> + <Label>Comments for Author</Label> <ValidatedField component={TextAreaField} name="messageToHE"