diff --git a/packages/component-faraday-selectors/src/index.js b/packages/component-faraday-selectors/src/index.js index d95643452340c8c5607971adb3da46092e2a4801..8b683eda9911688c45e3fedafcf0163473c69e68 100644 --- a/packages/component-faraday-selectors/src/index.js +++ b/packages/component-faraday-selectors/src/index.js @@ -1,4 +1,4 @@ -import { get } from 'lodash' +import { get, last } from 'lodash' export const isHEToManuscript = (state, collectionId) => { const currentUserId = get(state, 'currentUser.user.id') @@ -7,9 +7,10 @@ export const isHEToManuscript = (state, collectionId) => { return get(collection, 'handlingEditor.id') === currentUserId } -export const canMakeRecommendation = (state, project) => { - const isHE = isHEToManuscript(state, project.id) - return isHE && get(project, 'status') === 'reviewCompleted' +export const canMakeRecommendation = (state, collection, fragment) => { + if (fragment.id !== last(collection.fragments)) return false + const isHE = isHEToManuscript(state, collection.id) + return isHE && get(collection, 'status') === 'reviewCompleted' } export const currentUserIs = ({ currentUser: { user } }, role) => { @@ -57,7 +58,8 @@ export const getHERecommendation = (state, collectionId, fragmentId) => { } const cantMakeDecisionStatuses = ['rejected', 'published', 'draft'] -export const canMakeDecision = (state, collection) => { +export const canMakeDecision = (state, collection, fragment) => { + if (fragment.id !== last(collection.fragments)) return false const status = get(collection, 'status') if (!status || cantMakeDecisionStatuses.includes(status)) return false diff --git a/packages/component-manuscript/src/components/ManuscriptLayout.js b/packages/component-manuscript/src/components/ManuscriptLayout.js index ea90b83967e7dbbd429f89747956d3c7f97968f9..b19fd29804eb846d78f727332c4ce29a2ca405ea 100644 --- a/packages/component-manuscript/src/components/ManuscriptLayout.js +++ b/packages/component-manuscript/src/components/ManuscriptLayout.js @@ -20,6 +20,7 @@ import { ManuscriptDetails, ManuscriptVersion, EditorialComments, + ResponseToReviewers, } from './' const ManuscriptLayout = ({ @@ -29,6 +30,8 @@ const ManuscriptLayout = ({ editorInChief, canMakeRevision, editorialRecommendations, + responseToReviewers, + hasResponseToReviewers, project = {}, version = {}, }) => ( @@ -45,7 +48,7 @@ const ManuscriptLayout = ({ <ManuscriptId>{`- ID ${project.customId}`}</ManuscriptId> </LeftDetails> <RightDetails> - <ManuscriptVersion project={project} /> + <ManuscriptVersion project={project} version={version} /> </RightDetails> </Header> <ManuscriptHeader @@ -57,10 +60,6 @@ const ManuscriptLayout = ({ fragment={version} startExpanded={isEmpty(version.revision)} /> - {canMakeRevision && ( - <SubmitRevision project={project} version={version} /> - )} - <ReviewsAndReports project={project} version={version} /> {editorialRecommendations.length > 0 && ( <EditorialComments editorInChief={editorInChief} @@ -68,6 +67,11 @@ const ManuscriptLayout = ({ recommendations={editorialRecommendations} /> )} + <ReviewsAndReports project={project} version={version} /> + {canMakeRevision && ( + <SubmitRevision project={project} version={version} /> + )} + {hasResponseToReviewers && <ResponseToReviewers version={version} />} </Container> <SideBar flex={1}> <SideBarActions project={project} version={version} /> diff --git a/packages/component-manuscript/src/components/ManuscriptPage.js b/packages/component-manuscript/src/components/ManuscriptPage.js index b6ff4faa6b97eed352a2ce4468fc2e97328484c8..b09fe2d5c3a1b7491b7ad99e394f68cb0116f7af 100644 --- a/packages/component-manuscript/src/components/ManuscriptPage.js +++ b/packages/component-manuscript/src/components/ManuscriptPage.js @@ -1,8 +1,8 @@ import { connect } from 'react-redux' -import { head, get } from 'lodash' import { actions } from 'pubsweet-client' import { ConnectPage } from 'xpub-connect' import { withJournal } from 'xpub-journal' +import { head, get, isEmpty } from 'lodash' import { replace } from 'react-router-redux' import { withRouter } from 'react-router-dom' import { @@ -13,8 +13,9 @@ import { import { get as apiGet } from 'pubsweet-client/src/helpers/api' import { compose, - lifecycle, withState, + lifecycle, + withProps, withHandlers, setDisplayName, } from 'recompose' @@ -129,4 +130,9 @@ export default compose( ) }, }), + withProps(({ version }) => ({ + hasResponseToReviewers: + !isEmpty(get(version, 'files.responseToReviewers')) || + get(version, 'commentsToReviewers'), + })), )(ManuscriptLayout) diff --git a/packages/component-manuscript/src/components/ManuscriptVersion.js b/packages/component-manuscript/src/components/ManuscriptVersion.js index 7da222858c5e88a9860e934b3671867c643732dd..2e85ed689403deae18e0518ae04a03c43063da98 100644 --- a/packages/component-manuscript/src/components/ManuscriptVersion.js +++ b/packages/component-manuscript/src/components/ManuscriptVersion.js @@ -1,28 +1,28 @@ import React from 'react' import { get } from 'lodash' import { Menu } from '@pubsweet/ui' -import { compose } from 'recompose' -import { connect } from 'react-redux' import { withRouter } from 'react-router-dom' -import { selectFragments } from 'xpub-selectors' import { parseVersionOptions } from './utils' -const ManuscriptVersion = ({ project = {}, fragments = [], history, match }) => - !!fragments.length && ( - <Menu - inline - onChange={v => - history.push(`/projects/${project.id}/versions/${v}/details`) - } - options={parseVersionOptions(fragments)} - value={get(match, 'params.version')} - /> +const ManuscriptVersion = ({ + history, + version = {}, + project = { fragments: [] }, +}) => { + const fragments = get(project, 'fragments') + return ( + !!fragments.length && ( + <Menu + inline + onChange={v => + history.push(`/projects/${project.id}/versions/${v}/details`) + } + options={parseVersionOptions(fragments)} + value={get(version, 'id')} + /> + ) ) +} -export default compose( - withRouter, - connect((state, { project }) => ({ - fragments: selectFragments(state, get(project, 'fragments') || []), - })), -)(ManuscriptVersion) +export default withRouter(ManuscriptVersion) diff --git a/packages/component-manuscript/src/components/ResponseToReviewers.js b/packages/component-manuscript/src/components/ResponseToReviewers.js new file mode 100644 index 0000000000000000000000000000000000000000..f2f200fb98ae56aaa73a4ca1f3f12842ac0afe9a --- /dev/null +++ b/packages/component-manuscript/src/components/ResponseToReviewers.js @@ -0,0 +1,67 @@ +import React, { Fragment } from 'react' +import { get, isEmpty } from 'lodash' +import { withProps } from 'recompose' +import { th } from '@pubsweet/ui-toolkit' +import styled, { css } from 'styled-components' +import { FileItem } from 'pubsweet-components-faraday/src/components/Files' + +import { Expandable } from '../molecules' + +const ResponseToReviewers = ({ + responseToReviewers: { comments = '', files }, +}) => ( + <Root> + <Expandable label="Respone to reviewers"> + {comments && ( + <Fragment> + <Label>Comments to reviewers</Label> + <Text>{comments}</Text> + </Fragment> + )} + {!isEmpty(files) && ( + <Fragment> + <Label>Files</Label> + {files.map(file => ( + <FileItem compact id={file.id} key={file.id} {...file} /> + ))} + </Fragment> + )} + </Expandable> + </Root> +) + +export default withProps(({ version }) => ({ + responseToReviewers: { + comments: get(version, 'commentsToReviewers'), + files: get(version, 'files.responseToReviewers'), + }, +}))(ResponseToReviewers) + +// #region styled-components +const defaultText = css` + color: ${th('colorPrimary')}; + font-family: ${th('fontReading')}; + font-size: ${th('fontSizeBaseSmall')}; +` +const Root = styled.div` + background-color: ${th('colorBackground')}; + margin-top: calc(${th('subGridUnit')} * 2); + transition: height 0.3s; +` + +const Label = styled.div` + ${defaultText}; + text-transform: uppercase; + i { + text-transform: none; + margin-left: ${th('gridUnit')}; + } +` + +const Text = styled.div` + ${defaultText}; + span { + margin-left: calc(${th('subGridUnit')}*3); + } +` +// #endregion diff --git a/packages/component-manuscript/src/components/SideBarActions.js b/packages/component-manuscript/src/components/SideBarActions.js index b3e9036a0a353e26d401bd021cd2de8622f9a6d7..d5e8b16b033cf934842da48a3126b4fd686545d0 100644 --- a/packages/component-manuscript/src/components/SideBarActions.js +++ b/packages/component-manuscript/src/components/SideBarActions.js @@ -57,8 +57,8 @@ export default compose( withRouter, connect( (state, { project, version }) => ({ - canMakeDecision: canMakeDecision(state, project), - canMakeRecommendation: canMakeRecommendation(state, project), + canMakeDecision: canMakeDecision(state, project, version), + canMakeRecommendation: canMakeRecommendation(state, project, version), }), (dispatch, { project, version, history }) => ({ createRevision: () => dispatch(createRevision(project, version, history)), diff --git a/packages/component-manuscript/src/components/SubmitRevision.js b/packages/component-manuscript/src/components/SubmitRevision.js index 0d5c6d5889f9ca5a24c07d002812b3bae4a7dacb..057f2a36d5a86563f779bd11c03d6c062f1b5809 100644 --- a/packages/component-manuscript/src/components/SubmitRevision.js +++ b/packages/component-manuscript/src/components/SubmitRevision.js @@ -1,7 +1,7 @@ // #region imports import React from 'react' -import { get } from 'lodash' import PropTypes from 'prop-types' +import { get, isEmpty } from 'lodash' import { connect } from 'react-redux' import { th } from '@pubsweet/ui-toolkit' import { required } from 'xpub-validators' @@ -56,9 +56,11 @@ const SubmitRevision = ({ project, version, formError, + formValues, removeFile, handleSubmit, responseFiles, + submitFailed, }) => ( <Root> <Expandable label="Submit Revision" startExpanded> @@ -104,7 +106,11 @@ const SubmitRevision = ({ <ValidatedField component={TextAreaField} name="commentsToReviewers" - validate={[required]} + validate={ + isEmpty(get(formValues, 'files.responseToReviewers')) + ? [required] + : [] + } /> </FullWidth> </Row> @@ -127,7 +133,8 @@ const SubmitRevision = ({ </FilePicker> </Expandable> <SubmitContainer> - {formError && <Error>There are some errors above.</Error>} + {submitFailed && + formError && <Error>There are some errors above.</Error>} <AutosaveIndicator formName="revision" /> <Button onClick={handleSubmit} primary> SUBMIT REVISION diff --git a/packages/component-manuscript/src/components/index.js b/packages/component-manuscript/src/components/index.js index 8c668d3d54aff7712e20f3e6060f601772499f61..402226d9ce88607be4c13e78350c622edbb82f9a 100644 --- a/packages/component-manuscript/src/components/index.js +++ b/packages/component-manuscript/src/components/index.js @@ -15,3 +15,4 @@ export { default as ReviewsAndReports } from './ReviewsAndReports' export { default as EditorialComments } from './EditorialComments' export { default as ReviewReportsList } from './ReviewReportsList' export { default as ReviewerReportForm } from './ReviewerReportForm' +export { default as ResponseToReviewers } from './ResponseToReviewers' diff --git a/packages/component-manuscript/src/components/utils.js b/packages/component-manuscript/src/components/utils.js index 3ad73509bb38957d078a00e46797914f37e5bbc3..bbe6eb5ec3fefc5575447214e3279fbea151b2cf 100644 --- a/packages/component-manuscript/src/components/utils.js +++ b/packages/component-manuscript/src/components/utils.js @@ -80,10 +80,12 @@ export const parseSearchParams = url => { } export const parseVersionOptions = (fragments = []) => - fragments.map(f => ({ - value: f.id, - label: `Version ${f.version}`, - })) + fragments + .map((f, index) => ({ + value: f, + label: `Version ${index + 1}`, + })) + .reverse() const alreadyAnswered = `You have already answered this invitation.` export const redirectToError = redirectFn => err => { diff --git a/packages/components-faraday/src/components/Dashboard/DashboardCard.js b/packages/components-faraday/src/components/Dashboard/DashboardCard.js index 59638dda62cd0f0059f530d3a11105723c954d82..b3e877877e64a2776973abf0287a77f8f588c9b4 100644 --- a/packages/components-faraday/src/components/Dashboard/DashboardCard.js +++ b/packages/components-faraday/src/components/Dashboard/DashboardCard.js @@ -193,11 +193,11 @@ export default compose( getContext({ journal: PropTypes.object, currentUser: PropTypes.object }), withTheme, connect((state, { project, version }) => ({ - canMakeDecision: canMakeDecision(state, project), isHE: isHEToManuscript(state, get(project, 'id')), canInviteReviewers: canInviteReviewers(state, project), invitation: selectInvitation(state, get(version, 'id')), - canMakeRecommendation: canMakeRecommendation(state, project), + canMakeDecision: canMakeDecision(state, project, version), + canMakeRecommendation: canMakeRecommendation(state, project, version), })), )(DashboardCard)