diff --git a/packages/component-wizard/src/components/WizardFormStep.js b/packages/component-wizard/src/components/WizardFormStep.js index ac1a7fc9ea7ed216ed8c70a2045ad04eef643c6e..04bd7a4904a10928de6606e378d9353743daca3b 100644 --- a/packages/component-wizard/src/components/WizardFormStep.js +++ b/packages/component-wizard/src/components/WizardFormStep.js @@ -2,7 +2,7 @@ import PropTypes from 'prop-types' import { connect } from 'react-redux' import { debounce, pick, get } from 'lodash' import { actions } from 'pubsweet-client' -import { reduxForm, formValueSelector } from 'redux-form' +import { reduxForm, formValueSelector, SubmissionError } from 'redux-form' import { compose, getContext, withProps } from 'recompose' import WizardStep from './WizardStep' @@ -19,14 +19,55 @@ const onChange = (values, dispatch, { project, version }) => { ) } +const submitManuscript = (values, dispatch, project, version, history) => { + dispatch( + actions.updateFragment(project, { + id: version.id, + rev: version.rev, + submitted: new Date(), + ...values, + }), + ) + .then(() => + dispatch( + actions.updateCollection({ + id: project.id, + rev: project.rev, + status: 'submitted', + }), + ), + ) + .then(() => { + history.push('/') + }) + .catch(error => { + if (error.validationErrors) { + throw new SubmissionError() + } + }) +} + +const onSubmit = ( + values, + dispatch, + { nextStep, isFinal, history, project, version, ...rest }, +) => { + if (!isFinal) { + nextStep() + } else { + submitManuscript(values, dispatch, project, version, history) + } +} + export default compose( getContext({ - goBack: PropTypes.func, + history: PropTypes.object, isFinal: PropTypes.bool, isFirst: PropTypes.bool, project: PropTypes.object, version: PropTypes.object, wizard: PropTypes.object, + dispatchFns: PropTypes.object, }), withProps(({ version, wizard }) => ({ initialValues: pick(version, wizard.formSectionKeys), @@ -43,17 +84,8 @@ export default compose( })), reduxForm({ form: 'wizard', - destroyOnUnmount: false, forceUnregisterOnUnmount: true, - onSubmit: ( - values, - dispatch, - { nextStep, isFinal, formValues, ...rest }, - ) => { - if (!isFinal) { - nextStep() - } - }, onChange: debounce(onChange, 1000, { maxWait: 5000 }), + onSubmit, }), )(WizardStep) diff --git a/packages/component-wizard/src/components/WizardPage.js b/packages/component-wizard/src/components/WizardPage.js index 584d531c3f0c131762dd4fa2101ec67dc40d382c..2e331f13f8e0e27e3d6dfe3bcff8673a3561b95c 100644 --- a/packages/component-wizard/src/components/WizardPage.js +++ b/packages/component-wizard/src/components/WizardPage.js @@ -1,5 +1,6 @@ import PropTypes from 'prop-types' import { connect } from 'react-redux' +import { bindActionCreators } from 'redux' import { actions } from 'pubsweet-client' import { withJournal } from 'xpub-journal' import { ConnectPage } from 'xpub-connect' @@ -23,6 +24,7 @@ export default compose( { id: match.params.version }, ), ]), + withJournal, connect( (state, { match }) => { const project = selectCollection(state, match.params.project) @@ -30,9 +32,15 @@ export default compose( return { project, version } }, - { setAuthors }, + (dispatch, { journal: { wizard } }) => ({ + dispatchFns: wizard.dispatchFunctions.reduce((acc, f) => { + acc[f.name] = bindActionCreators(f, dispatch) + return acc + }, {}), + setAuthors: (authors, fragmentId) => + dispatch(setAuthors(authors, fragmentId)), + }), ), - withJournal, lifecycle({ componentDidMount() { const { version, setAuthors } = this.props @@ -51,20 +59,29 @@ export default compose( }), withContext( { - goBack: PropTypes.func, + history: PropTypes.object, isFinal: PropTypes.bool, isFirst: PropTypes.bool, project: PropTypes.object, version: PropTypes.object, wizard: PropTypes.object, + dispatchFns: PropTypes.object, }, - ({ history: { goBack }, step, project, version, journal: { wizard } }) => ({ - goBack, + ({ + history, + step, + project, + version, + journal: { wizard }, + dispatchFns, + }) => ({ + history, isFinal: step === wizard.steps.length - 1, isFirst: step === 0, project, version, wizard, + dispatchFns, }), ), )(Wizard) diff --git a/packages/component-wizard/src/components/WizardStep.js b/packages/component-wizard/src/components/WizardStep.js index fc65ed1a7fd461e2c3d4bb442c28cafc9879893b..afd2ba1fe3f436b1ff91c94b5aba45c21cad197c 100644 --- a/packages/component-wizard/src/components/WizardStep.js +++ b/packages/component-wizard/src/components/WizardStep.js @@ -8,18 +8,25 @@ import classes from './WizardStep.local.scss' export default ({ children: stepChildren, title, + subtitle, buttons, nextStep, prevStep, handleSubmit, isFinal, isFirst, - goBack, + history, formValues, + wizard, + dispatchFns, }) => ( <div className={classnames(classes.step)}> <form className={classnames(classes.form)} onSubmit={handleSubmit}> <h3 className={classnames(classes.title)}>{title}</h3> + <p + className={classnames(classes.subtitle)} + dangerouslySetInnerHTML={{ __html: subtitle }} // eslint-disable-line + /> {stepChildren && stepChildren.map( ({ @@ -27,7 +34,8 @@ export default ({ validate, dependsOn, renderComponent: Comp, - type, + format, + parse, ...rest }) => { if ( @@ -38,20 +46,28 @@ export default ({ } return ( <ValidatedField - component={input => <Comp {...rest} {...input} />} + component={input => ( + <Comp {...rest} {...input} {...dispatchFns} /> + )} + format={format} key={fieldId} name={fieldId} + parse={parse} validate={validate} /> ) }, )} <div className={classnames(classes.buttons)}> - <Button onClick={isFirst ? goBack : prevStep}> - {isFirst ? 'Cancel' : 'Back'} + <Button onClick={isFirst ? () => history.push('/') : prevStep}> + {isFirst + ? `${wizard.cancelText || 'Cancel'}` + : `${wizard.backText || 'Back'}`} </Button> <Button primary type="submit"> - {isFinal ? 'Finish' : 'Next'} + {isFinal + ? `${wizard.submitText || 'Submit Manuscript'}` + : `${wizard.nextText || 'Next'}`} </Button> </div> </form> diff --git a/packages/component-wizard/src/components/WizardStep.local.scss b/packages/component-wizard/src/components/WizardStep.local.scss index 1b69b7a3a10de57d2fc98531d1d5c2454ce9ac39..48627e47b6862fd47c8ce036a35e72fd342d1ab2 100644 --- a/packages/component-wizard/src/components/WizardStep.local.scss +++ b/packages/component-wizard/src/components/WizardStep.local.scss @@ -10,6 +10,11 @@ .title { align-self: center; } + + .subtitle { + align-self: center; + margin-bottom: 25px; + } } .form { diff --git a/packages/xpub-faraday/app/app.js b/packages/xpub-faraday/app/app.js index 6ca64de09e621859c51fcd7b0a9440c18ca96608..fb7eae11ea0bf59533f689f99ac71e48b38a0ed4 100644 --- a/packages/xpub-faraday/app/app.js +++ b/packages/xpub-faraday/app/app.js @@ -11,7 +11,7 @@ import * as journal from './config/journal' import Routes from './routes' const history = createHistory() -export const store = configureStore(history, {}) +const store = configureStore(history, {}) const theme = {} const render = () => { diff --git a/packages/xpub-faraday/app/config/journal/article-sections-tbrm.js b/packages/xpub-faraday/app/config/journal/article-sections-tbrm.js new file mode 100644 index 0000000000000000000000000000000000000000..ab5c5e94d62fc58cf8bb7b12a7ac462f1ddba050 --- /dev/null +++ b/packages/xpub-faraday/app/config/journal/article-sections-tbrm.js @@ -0,0 +1,30 @@ +export default [ + { + label: 'Cognitive Psychology', + value: 'cognitive-psychology', + }, + { + label: 'Social Psychology', + value: 'social-psychology', + }, + { + label: 'Personality Psychology', + value: 'personality-psychology', + }, + { + label: 'Developmental Psychology', + value: 'developmental-psychology', + }, + { + label: 'Clinical Psychology', + value: 'clinical-psychology', + }, + { + label: 'Organizational Behavior', + value: 'organizational-behavior', + }, + { + label: 'Methodology and Research Practice', + value: 'methodology', + }, +] diff --git a/packages/xpub-faraday/app/config/journal/article-types-tbrm.js b/packages/xpub-faraday/app/config/journal/article-types-tbrm.js new file mode 100644 index 0000000000000000000000000000000000000000..a5d08e5f9823fcce6aa1ff85435a1b798ac5629a --- /dev/null +++ b/packages/xpub-faraday/app/config/journal/article-types-tbrm.js @@ -0,0 +1,18 @@ +export default [ + { + label: 'Original Research Report', + value: 'original-research', + }, + { + label: 'Review', + value: 'review', + }, + { + label: 'Opinion/Commentary', + value: 'opinion', + }, + { + label: 'Registered Report', + value: 'registered-report', + }, +] diff --git a/packages/xpub-faraday/app/config/journal/index.js b/packages/xpub-faraday/app/config/journal/index.js index fccf0c181b0ce99568dfa87bc07510ba18cbdd30..874f461288cd76f59551a4018215c1ff5408c99e 100644 --- a/packages/xpub-faraday/app/config/journal/index.js +++ b/packages/xpub-faraday/app/config/journal/index.js @@ -7,4 +7,6 @@ export { default as editors } from './editors' export { default as roles } from './roles' export { default as wizard } from './submit-wizard' export { default as issueTypes } from './issues-types' +export { default as articleTypes } from './article-types-tbrm' +export { default as articleSections } from './article-sections-tbrm' export { default as manuscriptTypes } from './manuscript-types' diff --git a/packages/xpub-faraday/app/config/journal/submit-wizard.js b/packages/xpub-faraday/app/config/journal/submit-wizard.js index 73318a55ec5ed0f135e8c0b247f321f96622d35a..6de83e0e56f36c8eb57dc1f728a7c1729619c247 100644 --- a/packages/xpub-faraday/app/config/journal/submit-wizard.js +++ b/packages/xpub-faraday/app/config/journal/submit-wizard.js @@ -7,7 +7,7 @@ import { TextField, Supplementary, } from '@pubsweet/ui' -import uploadFile from 'xpub-upload' +import uploadFileFn from 'xpub-upload' import { required, minChars, minSize } from 'xpub-validators' import { AuthorList } from 'pubsweet-component-wizard/src/components' @@ -34,9 +34,12 @@ const journal = { value: 'hindawi-faraday', } +const uploadFile = input => uploadFileFn(input) + export default { showProgress: true, formSectionKeys: ['metadata', 'declarations', 'conflicts', 'notes', 'files'], + dispatchFunctions: [uploadFile], steps: [ { label: 'Journal details', @@ -107,6 +110,7 @@ export default { fieldId: 'conflicts.hasConflicts', renderComponent: yesNoWithLabel, label: 'Is there a potential conflict of interest?', + validate: [required], }, { dependsOn: { @@ -125,22 +129,19 @@ export default { title: 'Manuscript Files Upload', children: [ { - fieldId: 'mainManuscripts', + fieldId: 'files.manuscripts', label: 'Main Manuscript', renderComponent: Supplementary, - uploadFile, }, { - fieldId: 'supplementalFiles', + fieldId: 'files.supplementary', label: 'Supplemental Files', renderComponent: Supplementary, - uploadFile, }, { - fieldId: 'coverLetter', + fieldId: 'files.coverLetter', label: 'Cover Letter', renderComponent: Supplementary, - uploadFile, }, ], }, diff --git a/packages/xpub-faraday/app/config/journal/wizard-validators.js b/packages/xpub-faraday/app/config/journal/wizard-validators.js index 9a9b0a9d4b086dda7d1efa2309355d0a1c14ceef..4f11c7640ccd08799e6a1b10aef91901552ad6f4 100644 --- a/packages/xpub-faraday/app/config/journal/wizard-validators.js +++ b/packages/xpub-faraday/app/config/journal/wizard-validators.js @@ -1,4 +1,4 @@ -import { get } from 'lodash' +import { get, isEmpty } from 'lodash' import manuscriptTypes from './manuscript-types' @@ -7,7 +7,10 @@ const requiredTypes = manuscriptTypes .map(t => t.value) export const requiredBasedOnType = (value, formValues) => { - if (requiredTypes.includes(get(formValues, 'metadata.type'))) { + if ( + requiredTypes.includes(get(formValues, 'metadata.type')) && + isEmpty(get(formValues, 'metadata.abstract')) + ) { return 'Required' } return undefined diff --git a/packages/xpub-faraday/config/validations.js b/packages/xpub-faraday/config/validations.js index f9d3945aafba228c1ca996a5370ba4119198754f..8e82f6e4606256b1c0f2e0d3f60a28879f972057 100644 --- a/packages/xpub-faraday/config/validations.js +++ b/packages/xpub-faraday/config/validations.js @@ -29,12 +29,15 @@ module.exports = { message: Joi.string(), }), files: Joi.object({ - manuscript: Joi.object({ - name: Joi.string().required(), - type: Joi.string(), - size: Joi.number(), - url: Joi.string(), - }), + manuscript: Joi.any(), + manuscripts: Joi.array().items( + Joi.object({ + name: Joi.string().required(), + type: Joi.string(), + size: Joi.number(), + url: Joi.string(), + }), + ), supplementary: Joi.array().items( Joi.object({ name: Joi.string().required(), @@ -43,6 +46,14 @@ module.exports = { url: Joi.string(), }), ), + coverLetter: Joi.array().items( + Joi.object({ + name: Joi.string().required(), + type: Joi.string(), + size: Joi.number(), + url: Joi.string(), + }), + ), }), notes: Joi.object({ fundingAcknowledgement: Joi.string(),