diff --git a/packages/component-wizard/src/components/WizardFormStep.js b/packages/component-wizard/src/components/WizardFormStep.js index e87290a13955d609c3f6fd59b93edf7afa502128..d5e71660176306c455f4cb3af9d443c9c8310df6 100644 --- a/packages/component-wizard/src/components/WizardFormStep.js +++ b/packages/component-wizard/src/components/WizardFormStep.js @@ -7,6 +7,7 @@ import { reduxForm, formValueSelector, SubmissionError } from 'redux-form' import WizardStep from './WizardStep' import { autosaveRequest } from '../redux/autosave' +import { submitRevision, isRevisionFlow } from '../redux/conversion' const wizardSelector = formValueSelector('wizard') @@ -29,14 +30,14 @@ const onChange = ( } } -const submitManuscript = ( +const submitManuscript = ({ values, - dispatch, - project, version, + project, history, + dispatch, redirectPath = '/', -) => { +}) => { dispatch( actions.updateFragment(project, { id: version.id, @@ -66,18 +67,34 @@ const submitManuscript = ( }) } +const submitFragmentRevision = ({ + version, + project, + history, + redirectPath = '/', +}) => { + submitRevision(project.id, version.id).then(() => { + history.push(redirectPath, { + project: project.id, + customId: project.customId, + version: version.id, + }) + }) +} + const onSubmit = ( values, dispatch, { - nextStep, isFinal, history, project, version, + nextStep, confirmation, - wizard: { confirmationModal, submissionRedirect, formSectionKeys }, + isRevisionFlow, toggleConfirmation, + wizard: { confirmationModal, submissionRedirect, formSectionKeys }, ...rest }, ) => { @@ -85,16 +102,22 @@ const onSubmit = ( nextStep() } else if (confirmationModal && !confirmation) { toggleConfirmation() - } else { - const newValues = pick(values, formSectionKeys) - submitManuscript( - newValues, - dispatch, + } else if (isRevisionFlow) { + submitFragmentRevision({ + version, project, + history, + redirectPath: submissionRedirect, + }) + } else { + submitManuscript({ version, + project, history, - submissionRedirect, - ) + dispatch, + redirectPath: submissionRedirect, + values: pick(values, formSectionKeys), + }) } } @@ -111,13 +134,35 @@ export default compose( confirmation: PropTypes.bool, toggleConfirmation: PropTypes.func, }), - withProps(({ version, wizard }) => ({ - readonly: !!get(version, 'submitted'), - initialValues: pick(version, wizard.formSectionKeys), - })), - connect((state, { wizard: { formSectionKeys } }) => ({ + connect((state, { wizard: { formSectionKeys }, project, version }) => ({ formValues: wizardSelector(state, ...formSectionKeys), + isRevisionFlow: isRevisionFlow(state, project, version), })), + withProps( + ({ + version, + isFirst, + isFinal, + isRevisionFlow, + wizard: { + formSectionKeys, + backText = 'Back', + nextText = 'Next', + cancelText = 'Cancel', + submitText = 'Submit Manuscript', + revisionText = 'Submit Revision', + }, + }) => ({ + readonly: !!get(version, 'submitted'), + initialValues: pick(version, formSectionKeys), + buttons: { + backText: isFirst ? cancelText : backText, + nextText: !isFinal // eslint-disable-line + ? nextText + : isRevisionFlow ? revisionText : submitText, + }, + }), + ), reduxForm({ form: 'wizard', forceUnregisterOnUnmount: true, diff --git a/packages/component-wizard/src/components/WizardStep.js b/packages/component-wizard/src/components/WizardStep.js index 1f8a35281318010fd7cdb2e00a89ce3df6e9c9d3..a9a873575b7e77019ba0a515635dbf798ca4eb67 100644 --- a/packages/component-wizard/src/components/WizardStep.js +++ b/packages/component-wizard/src/components/WizardStep.js @@ -6,21 +6,22 @@ import { ValidatedField, Button, th } from '@pubsweet/ui' import AutosaveIndicator from './AutosaveIndicator' export default ({ - children: stepChildren, title, - subtitle, - buttons, - nextStep, - prevStep, - handleSubmit, + wizard, isFinal, isFirst, history, + nextStep, + subtitle, + prevStep, formValues, - wizard, dispatchFns, + handleSubmit, confirmation, + isRevisionFlow, toggleConfirmation, + children: stepChildren, + buttons: { backText, nextText }, wizard: { confirmationModal: ConfirmationModal }, ...rest }) => ( @@ -69,14 +70,10 @@ export default ({ data-test="button-prev" onClick={isFirst ? () => history.push('/') : prevStep} > - {isFirst - ? `${wizard.cancelText || 'Cancel'}` - : `${wizard.backText || 'Back'}`} + {backText} </Button> <Button data-test="button-next" primary type="submit"> - {isFinal - ? `${wizard.submitText || 'Submit Manuscript'}` - : `${wizard.nextText || 'Next'}`} + {nextText} </Button> </ButtonContainer> {confirmation && ( diff --git a/packages/component-wizard/src/redux/conversion.js b/packages/component-wizard/src/redux/conversion.js index 87f5ac3843b481f59c5b0ca9584266b3049ed3a0..7f8f205c5c2f595ec7c40fe562c7069c3872662e 100644 --- a/packages/component-wizard/src/redux/conversion.js +++ b/packages/component-wizard/src/redux/conversion.js @@ -1,7 +1,7 @@ import moment from 'moment' import { pick } from 'lodash' import { actions } from 'pubsweet-client' -import { create } from 'pubsweet-client/src/helpers/api' +import { create, update } from 'pubsweet-client/src/helpers/api' /* constants */ export const CREATE_DRAFT_REQUEST = 'CREATE_DRAFT_REQUEST' @@ -12,11 +12,6 @@ export const createDraftRequest = () => ({ type: CREATE_DRAFT_REQUEST, }) -export const createDraftSuccess = draft => ({ - type: CREATE_DRAFT_SUCCESS, - draft, -}) - /* utils */ const generateCustomId = () => moment @@ -24,6 +19,10 @@ const generateCustomId = () => .toString() .slice(-7) +export const isRevisionFlow = (state, collection, fragment) => + collection.fragments.length > 1 && !fragment.submitted + +/* actions */ const addSubmittingAuthor = (user, collectionId, fragmentId) => { const author = { ...pick(user, ['id', 'email', 'affiliation', 'firstName', 'lastName']), @@ -36,7 +35,6 @@ const addSubmittingAuthor = (user, collectionId, fragmentId) => { }) } -/* actions */ export const createDraftSubmission = history => (dispatch, getState) => { const currentUser = getState().currentUser.user return dispatch( @@ -82,7 +80,8 @@ export const createRevision = ( previousVersion, history, ) => dispatch => { - const { id, submitted, ...prev } = previousVersion + // copy invitations only if minor revision + const { id, submitted, recommendations, ...prev } = previousVersion return dispatch( actions.createFragment(collection, { ...prev, @@ -98,6 +97,9 @@ export const createRevision = ( }) } +export const submitRevision = (collId, fragId) => + update(`/collections/${collId}/fragments/${fragId}/submit`) + /* reducer */ const initialState = { complete: undefined, diff --git a/packages/components-faraday/src/components/Files/Files.js b/packages/components-faraday/src/components/Files/Files.js index 9ce14c3240d6c3b78edd4f6f13e9ebbdbc8527cd..4294b9198bb8f27f007f50a7141bca3c907d3e9e 100644 --- a/packages/components-faraday/src/components/Files/Files.js +++ b/packages/components-faraday/src/components/Files/Files.js @@ -5,16 +5,17 @@ import { get, isEqual } from 'lodash' import { connect } from 'react-redux' import styled from 'styled-components' import { withRouter } from 'react-router-dom' -import { selectFragment } from 'xpub-selectors' import { change as changeForm } from 'redux-form' import { compose, lifecycle, withState, + getContext, withContext, withHandlers, } from 'recompose' import { SortableList } from 'pubsweet-components-faraday/src/components' +import { isRevisionFlow } from 'pubsweet-component-wizard/src/redux/conversion' import FileSection from './FileSection' import { @@ -31,6 +32,7 @@ const Files = ({ moveItem, removeFile, changeList, + isRevisionFlow, dropSortableFile, }) => ( <div> @@ -65,35 +67,42 @@ const Files = ({ changeList={changeList} dropSortableFile={dropSortableFile} files={get(files, 'coverLetter') || []} + isLast={!isRevisionFlow} listId="coverLetter" maxFiles={1} moveItem={moveItem('coverLetter')} removeFile={removeFile('coverLetter')} title="Cover letter" /> - <FileSection - addFile={addFile('coverLetter')} - allowedFileExtensions={['pdf', 'doc', 'docx']} - changeList={changeList} - dropSortableFile={dropSortableFile} - files={get(files, 'response') || []} - isLast - listId="responseToReviewer" - maxFiles={1} - moveItem={moveItem('response')} - removeFile={removeFile('response')} - title="Response to reviewers" - /> + {isRevisionFlow && ( + <FileSection + addFile={addFile('responseToReviewers')} + allowedFileExtensions={['pdf', 'doc', 'docx']} + changeList={changeList} + dropSortableFile={dropSortableFile} + files={get(files, 'responseToReviewers') || []} + isLast={isRevisionFlow} + listId="responseToReviewer" + maxFiles={1} + moveItem={moveItem('responseToReviewers')} + removeFile={removeFile('responseToReviewers')} + title="Response to reviewers" + /> + )} </div> ) export default compose( + getContext({ + version: PropTypes.object, + project: PropTypes.object, + }), withRouter, connect( - (state, { match }) => ({ + (state, { project, version }) => ({ error: getFileError(state), isFetching: getRequestStatus(state), - version: selectFragment(state, match.params.version), + isRevisionFlow: isRevisionFlow(state, project, version), }), { changeForm, @@ -105,6 +114,7 @@ export default compose( manuscripts: [], coverLetter: [], supplementary: [], + responseToReviewers: [], }), lifecycle({ componentDidMount() { @@ -113,6 +123,7 @@ export default compose( manuscripts: get(files, 'manuscripts') || [], coverLetter: get(files, 'coverLetter') || [], supplementary: get(files, 'supplementary') || [], + responseToReviewers: get(files, 'responseToReviewers') || [], })) }, componentWillReceiveProps(nextProps) { @@ -156,10 +167,10 @@ export default compose( }, addFile: ({ files, - uploadFile, + version, setFiles, + uploadFile, changeForm, - version, }) => type => file => { uploadFile(file, type, version.id) .then(file => { diff --git a/packages/xpub-faraday/config/upload-validations.js b/packages/xpub-faraday/config/upload-validations.js index 21b2412ef38c1f8aea0cf3f3e98faf486a3b7107..79f682e7416efb192c78574e39b13600fd4d473d 100644 --- a/packages/xpub-faraday/config/upload-validations.js +++ b/packages/xpub-faraday/config/upload-validations.js @@ -16,5 +16,12 @@ module.exports = { 'application/msword', ]) .error(new Error('Only Word documents and PDFs are allowed')), + responseToReviewers: Joi.any() + .valid([ + 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + 'application/pdf', + 'application/msword', + ]) + .error(new Error('Only Word documents and PDFs are allowed')), review: Joi.any(), } diff --git a/packages/xpub-faraday/config/validations.js b/packages/xpub-faraday/config/validations.js index b8d8d607061cd81a82c828686002baac69a89312..cba57c2f28fef01c0dc22ec4c5f3d22ce0510586 100644 --- a/packages/xpub-faraday/config/validations.js +++ b/packages/xpub-faraday/config/validations.js @@ -64,6 +64,16 @@ module.exports = { signedUrl: Joi.string(), }), ), + responseToReviewers: Joi.array().items( + Joi.object({ + id: Joi.string(), + name: Joi.string().required(), + type: Joi.string(), + size: Joi.number(), + url: Joi.string(), + signedUrl: Joi.string(), + }), + ), }), notes: Joi.object({ fundingAcknowledgement: Joi.string(),