diff --git a/packages/component-wizard/src/components/AuthorList.js b/packages/component-wizard/src/components/AuthorList.js index 879dba67eb9f3cb945d9c3d3575df5c35e7e30e6..9c0f19d8bf42934891e9c2f3d93554762490a0cf 100644 --- a/packages/component-wizard/src/components/AuthorList.js +++ b/packages/component-wizard/src/components/AuthorList.js @@ -7,7 +7,14 @@ import { reduxForm } from 'redux-form' import { actions } from 'pubsweet-client' import { required } from 'xpub-validators' import { withRouter } from 'react-router-dom' -import { compose, withHandlers, getContext, lifecycle } from 'recompose' +import { selectCurrentUser } from 'xpub-selectors' +import { + compose, + withHandlers, + withProps, + getContext, + lifecycle, +} from 'recompose' import { TextField, Menu, Icon, ValidatedField, Button } from '@pubsweet/ui' import { addAuthor, getFragmentAuthors, setAuthors } from '../redux/authors' @@ -48,7 +55,22 @@ const MenuItem = ({ label, name, options }) => ( </div> ) -const AuthorAdder = ({ authors, handleSubmit, ...rest }) => ( +const Label = ({ label, value }) => ( + <div className={classnames(classes['label-container'])}> + <span className={classnames(classes.label)}>{label}</span> + <span className={classnames(classes.value)}>{value}</span> + </div> +) + +const DragHandle = () => ( + <div className={classnames(classes['drag-handle'])}> + <Icon>chevron_up</Icon> + <Icon size={16}>menu</Icon> + <Icon>chevron_down</Icon> + </div> +) + +const AuthorAdder = ({ authors, handleSubmit }) => ( <div className={classnames(classes.adder)}> <Button onClick={handleSubmit} primary> {authors.length === 0 ? '+ Add submitting author' : '+ Add author'} @@ -83,20 +105,41 @@ const AuthorAdder = ({ authors, handleSubmit, ...rest }) => ( </div> ) -const Label = ({ label, value }) => ( - <div className={classnames(classes['label-container'])}> - <span className={classnames(classes.label)}>{label}</span> - <span className={classnames(classes.value)}>{value}</span> - </div> -) - -const DragHandle = () => ( - <div className={classnames(classes['drag-handle'])}> - <Icon>chevron_up</Icon> - <Icon size={16}>menu</Icon> - <Icon>chevron_down</Icon> - </div> -) +const Adder = compose( + connect(state => ({ + currentUser: selectCurrentUser(state), + })), + withProps(({ currentUser }) => { + const { admin, email, username } = currentUser + if (!admin) { + return { + initialValues: { + author: { + email, + firstName: username, + }, + }, + } + } + }), + reduxForm({ + form: 'author', + onSubmit: (values, dispatch, { authors, addAuthor, reset, match }) => { + const collectionId = get(match, 'params.project') + const fragmentId = get(match, 'params.version') + const isFirstAuthor = authors.length === 0 + addAuthor( + { + ...values.author, + isSubmitting: isFirstAuthor, + isCorresponding: isFirstAuthor, + }, + collectionId, + fragmentId, + ).then(reset) + }, + }), +)(AuthorAdder) const Author = ({ firstName, @@ -163,27 +206,6 @@ const Author = ({ </div> ) -const Adder = compose( - reduxForm({ - form: 'author', - destroyOnUnmount: false, - onSubmit: (values, dispatch, { authors, addAuthor, reset, match }) => { - const collectionId = get(match, 'params.project') - const fragmentId = get(match, 'params.version') - const isFirstAuthor = authors.length === 0 - addAuthor( - { - ...values.author, - isSubmitting: isFirstAuthor, - isCorresponding: isFirstAuthor, - }, - collectionId, - fragmentId, - ).then(reset) - }, - })(AuthorAdder), -) - const Authors = ({ author, authors, diff --git a/packages/component-wizard/src/components/WizardStep.js b/packages/component-wizard/src/components/WizardStep.js index afd2ba1fe3f436b1ff91c94b5aba45c21cad197c..dde7bcf9f1d1e829b39c09c06fdfe6508cedf943 100644 --- a/packages/component-wizard/src/components/WizardStep.js +++ b/packages/component-wizard/src/components/WizardStep.js @@ -23,10 +23,12 @@ export default ({ <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 - /> + {subtitle && ( + <div + className={classnames(classes.subtitle)} + dangerouslySetInnerHTML={{ __html: subtitle }} // eslint-disable-line + /> + )} {stepChildren && stepChildren.map( ({ diff --git a/packages/component-wizard/src/redux/authors.js b/packages/component-wizard/src/redux/authors.js index 2a7fb7c28d265541ce0c92cb75898eb35d52be8e..41d213512b9a2325aeaf5cb911b5a1db80d2179b 100644 --- a/packages/component-wizard/src/redux/authors.js +++ b/packages/component-wizard/src/redux/authors.js @@ -1,17 +1,23 @@ import { get } from 'lodash' import { actions } from 'pubsweet-client' import * as api from 'pubsweet-client/src/helpers/api' +import { change } from 'redux-form' // constants export const SET_AUTHORS = 'authors/SET_AUTHORS' -// actions -export const setAuthors = (authors, fragmentId) => ({ +const _setAuthors = (authors, fragmentId) => ({ type: SET_AUTHORS, authors, fragmentId, }) +// actions +export const setAuthors = (authors, fragmentId) => dispatch => { + dispatch(_setAuthors(authors, fragmentId)) + dispatch(change('wizard', 'authors', authors)) +} + export const addAuthor = (author, collectionId, fragmentId) => dispatch => api .create(`/fragments/${fragmentId}/authors`, author) diff --git a/packages/xpub-collabra/app/config/journal/submission-wizard.js b/packages/xpub-collabra/app/config/journal/submission-wizard.js new file mode 100644 index 0000000000000000000000000000000000000000..238c2542680f8a5374d0a16219369dfe7293df3c --- /dev/null +++ b/packages/xpub-collabra/app/config/journal/submission-wizard.js @@ -0,0 +1,328 @@ +import React from 'react' +import { AbstractEditor, TitleEditor, NoteEditor } from 'xpub-edit' +import { + Menu, + CheckboxGroup, + RadioGroup, + TextField, + Supplementary, +} from '@pubsweet/ui' +import uploadFileFn from 'xpub-upload' +import { + required, + minChars, + maxChars, + minSize, + join, + split, +} from 'xpub-validators' + +import articleTypes from './article-types' +import articleSections from './article-sections' +import declarations from './declarations' + +const minSize1 = minSize(1) +const minChars20 = minChars(20) +const minChars100 = minChars(100) +const maxChars500 = maxChars(500) +const maxChars5000 = maxChars(5000) +const joinComma = join(',') +const splitComma = split(',') + +const DeclarationInput = ({ label, ...rest }) => ( + <div style={{ display: 'flex', justifyContent: 'space-between' }}> + <label style={{ display: 'inline-block', marginTop: '15px' }}> + {label} + </label>{' '} + <RadioGroup inline {...rest} /> + </div> +) +const Spacing = () => <div style={{ width: '100%', height: '30px' }} /> +const Label = ({ label }) => ( + <label + style={{ display: 'inline-block', marginTop: '15px', marginBottom: '5px' }} + > + <b>{label}</b> + </label> +) +const SubLabel = ({ label }) => ( + <label + style={{ display: 'inline-block', marginTop: '10px', marginBottom: '5px' }} + > + {label} + </label> +) + +const uploadFile = input => uploadFileFn(input) + +export default { + showProgress: false, + submitText: 'Submit your manuscript', + backText: 'Back', + cancelText: 'Cancel', + nextText: 'Next', + formSectionKeys: [ + 'metadata', + 'declarations', + 'suggestions', + 'notes', + 'files', + ], + dispatchFunctions: [uploadFile], + steps: [ + { + label: 'Submission information', + title: 'Submission information', + subtitle: `We have ingested your manuscript. To access your manuscript in an editor, please view manuscript page. + <br/> To complete your submission, please answer the following questions. <br/> + The answers will be automatically saved.`, + children: [ + { + fieldId: 'metadata.title', + renderComponent: TitleEditor, + placeholder: 'Title', + title: 'Title', + validate: [required, minChars20, maxChars500], + }, + { + fieldId: 'spacing-0', + renderComponent: Spacing, + }, + { + fieldId: 'metadata.abstract', + renderComponent: AbstractEditor, + title: 'Abstract', + placeholder: 'Write an abstract', + validate: [required, minChars100, maxChars5000], + }, + { + fieldId: 'spacing-authors', + renderComponent: Spacing, + }, + { + fieldId: 'label-authors', + renderComponent: Label, + label: 'Authors', + }, + { + fieldId: 'metadata.authors', + renderComponent: TextField, + title: 'Authors', + placeholder: 'Enter author names...', + format: join(), + parse: split(), + validate: [minSize1], + }, + { + fieldId: 'spacing-Keywords', + renderComponent: Spacing, + }, + { + fieldId: 'label-Keywords', + renderComponent: Label, + label: 'Keywords', + }, + { + fieldId: 'metadata.keywords', + renderComponent: TextField, + title: 'Authors', + placeholder: 'Enter keywords...', + format: join(), + parse: split(), + validate: [minSize1], + }, + { + fieldId: 'spacing-article', + renderComponent: Spacing, + }, + { + fieldId: 'label-article', + renderComponent: Label, + label: 'Article Type', + }, + { + fieldId: 'metadata.articleType', + renderComponent: Menu, + options: articleTypes, + validate: [required], + }, + { + fieldId: 'spacing-section', + renderComponent: Spacing, + }, + { + fieldId: 'metadata.articleSection', + renderComponent: CheckboxGroup, + label: 'Section', + options: articleSections, + validate: [required], + }, + { + fieldId: 'spacing-decl', + renderComponent: Spacing, + }, + { + fieldId: `declarations.${declarations.questions[0].id}`, + label: declarations.questions[0].legend, + renderComponent: DeclarationInput, + options: [ + { value: 'yes', label: 'Yes' }, + { value: 'no', label: 'No' }, + ], + validate: [required], + }, + { + fieldId: `declarations.${declarations.questions[1].id}`, + label: declarations.questions[1].legend, + renderComponent: DeclarationInput, + options: [ + { value: 'yes', label: 'Yes' }, + { value: 'no', label: 'No' }, + ], + validate: [required], + }, + { + fieldId: `declarations.${declarations.questions[2].id}`, + label: declarations.questions[2].legend, + renderComponent: DeclarationInput, + options: [ + { value: 'yes', label: 'Yes' }, + { value: 'no', label: 'No' }, + ], + validate: [required], + }, + { + fieldId: `declarations.${declarations.questions[3].id}`, + label: declarations.questions[3].legend, + renderComponent: DeclarationInput, + options: [ + { value: 'yes', label: 'Yes' }, + { value: 'no', label: 'No' }, + ], + validate: [required], + }, + { + fieldId: `declarations.${declarations.questions[4].id}`, + label: declarations.questions[4].legend, + renderComponent: DeclarationInput, + options: [ + { value: 'yes', label: 'Yes' }, + { value: 'no', label: 'No' }, + ], + validate: [required], + }, + { + fieldId: `declarations.${declarations.questions[5].id}`, + label: declarations.questions[5].legend, + renderComponent: DeclarationInput, + options: [ + { value: 'yes', label: 'Yes' }, + { value: 'no', label: 'No' }, + ], + validate: [required], + }, + { + fieldId: 'spacing-rev', + renderComponent: Spacing, + }, + { + fieldId: 'label-reviewers', + renderComponent: Label, + label: 'Reviewers', + }, + { + fieldId: 'label-rev-suggested', + renderComponent: SubLabel, + label: 'Suggested reviewers', + }, + { + fieldId: 'suggestions.reviewers.suggested', + renderComponent: TextField, + title: 'Suggested reviewers', + placeholder: 'Add reviewers names...', + format: joinComma, + parse: splitComma, + }, + { + fieldId: 'label-rev-Opposed', + renderComponent: SubLabel, + label: 'Opposed reviewers', + }, + { + fieldId: 'suggestions.reviewers.opposed', + renderComponent: TextField, + title: 'Opposed reviewers', + placeholder: 'Add opposed reviewers names...', + format: joinComma, + parse: splitComma, + }, + { + fieldId: 'label-Editors', + renderComponent: Label, + label: 'Editors', + }, + { + fieldId: 'label-editors-suggested', + renderComponent: SubLabel, + label: 'Suggested Editors', + }, + { + fieldId: 'suggestions.editors.suggested', + renderComponent: TextField, + title: 'Suggested editors', + placeholder: 'Add editors names...', + format: joinComma, + parse: splitComma, + }, + { + fieldId: 'label-editors-Opposed', + renderComponent: SubLabel, + label: 'Opposed Editors', + }, + { + fieldId: 'suggestions.editors.opposed', + renderComponent: TextField, + title: 'Opposed editors', + placeholder: 'Add opposed editors names...', + format: joinComma, + parse: splitComma, + }, + { + fieldId: 'spacing-funding', + renderComponent: Spacing, + }, + { + fieldId: 'notes.fundingAcknowledgement', + renderComponent: NoteEditor, + title: 'Funding body acknowledgement (required)', + placeholder: 'Enter an acknowledgment...', + validate: [required], + }, + { + fieldId: 'spacing-special', + renderComponent: Spacing, + }, + { + fieldId: 'notes.specialInstructions', + renderComponent: NoteEditor, + title: 'Special instructions (confidential)', + placeholder: 'Enter instructions for the editor…', + }, + { + fieldId: 'spacing-files', + renderComponent: Spacing, + }, + { + fieldId: 'label-files', + renderComponent: Label, + label: 'Upload supplementary materials', + }, + { + fieldId: 'files.supplementary', + label: 'Upload supplementary materials', + renderComponent: Supplementary, + }, + ], + }, + ], +} diff --git a/packages/xpub-faraday/app/config/journal/submit-wizard.js b/packages/xpub-faraday/app/config/journal/submit-wizard.js index 6de83e0e56f36c8eb57dc1f728a7c1729619c247..24a8d827eae759efb1531c8fd41ade8bc093c209 100644 --- a/packages/xpub-faraday/app/config/journal/submit-wizard.js +++ b/packages/xpub-faraday/app/config/journal/submit-wizard.js @@ -28,6 +28,14 @@ const yesNoWithLabel = ({ label, ...rest }) => ( <YesOrNo {...rest} /> </div> ) +const Spacing = () => <div style={{ width: '100%', height: '15px' }} /> +const Label = ({ label }) => ( + <label + style={{ display: 'inline-block', marginTop: '15px', marginBottom: '5px' }} + > + <b>{label}</b> + </label> +) const journal = { label: 'Hindawi Faraday', @@ -45,18 +53,26 @@ export default { label: 'Journal details', title: 'Journal & Field Selection', children: [ + { + fieldId: 'label-Journal', + renderComponent: Label, + label: 'Journal', + }, { fieldId: 'metadata.journal', renderComponent: Menu, - label: 'Journal', options: [journal], value: journal.value, validate: [required], }, + { + fieldId: 'label-Issue', + renderComponent: Label, + label: 'Issue', + }, { fieldId: 'metadata.issue', renderComponent: Menu, - label: 'Issue', options: issueTypes, validate: [required], }, @@ -88,13 +104,25 @@ export default { placeholder: 'Manuscript title', title: 'Manuscript title', }, + { + fieldId: 'spacing-title', + renderComponent: Spacing, + }, + { + fieldId: 'label-manuscriptType', + renderComponent: Label, + label: 'Manuscript Type', + }, { fieldId: 'metadata.type', renderComponent: Menu, - label: 'Manuscript type', options: manuscriptTypes, validate: [required], }, + { + fieldId: 'spacing-type', + renderComponent: Spacing, + }, { fieldId: 'metadata.abstract', renderComponent: AbstractEditor, @@ -102,9 +130,18 @@ export default { placeholder: 'Write an abstract', validate: [requiredBasedOnType], }, + { + fieldId: 'spacing-abstract', + renderComponent: Spacing, + }, { fieldId: 'authors', renderComponent: AuthorList, + validate: [required], + }, + { + fieldId: 'spacing-authors', + renderComponent: Spacing, }, { fieldId: 'conflicts.hasConflicts',