diff --git a/packages/component-wizard/src/components/AuthorList.js b/packages/component-wizard/src/components/AuthorList.js deleted file mode 100644 index 560661e4e26186ae3fd53d309de6d0e0398d108d..0000000000000000000000000000000000000000 --- a/packages/component-wizard/src/components/AuthorList.js +++ /dev/null @@ -1,316 +0,0 @@ -import React from 'react' -import PropTypes from 'prop-types' -import classnames from 'classnames' -import { connect } from 'react-redux' -import { get } from 'lodash' -import { reduxForm } from 'redux-form' -import { actions } from 'pubsweet-client' -import { required } from 'xpub-validators' -import { withRouter } from 'react-router-dom' -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, - moveAuthors, -} from '../redux/authors' - -import classes from './AuthorList.local.scss' -import SortableList from './SortableList' - -const countries = [ - { label: 'Romania', value: 'ro' }, - { label: 'United Kingdom', value: 'uk' }, - { label: 'Germany', value: 'de' }, - { label: 'France', value: 'fr' }, -] - -const emailRegex = new RegExp(/^\w+([.-]?\w+)*@\w+([.-]?\w+)*(\.\w{2,3})+$/) - -const emailValidator = value => - emailRegex.test(value) ? undefined : 'Invalid email' - -const ValidatedTextField = ({ label, name, isRequired, validators = [] }) => { - const v = [isRequired && required, ...validators].filter(Boolean) - return ( - <div className={classnames(classes['validated-text'])}> - <span className={classnames(classes.label)}>{label}</span> - <ValidatedField component={TextField} name={name} validate={v} /> - </div> - ) -} - -const MenuItem = ({ label, name, options }) => ( - <div className={classnames(classes['validated-text'])}> - <span className={classnames(classes.label)}>{label}</span> - <ValidatedField - component={input => <Menu {...input} options={options} />} - name={name} - validate={[required]} - /> - </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 AuthorAdder = ({ authors, handleSubmit }) => ( - <div className={classnames(classes.adder)}> - <Button onClick={handleSubmit} primary> - {authors.length === 0 ? '+ Add submitting author' : '+ Add author'} - </Button> - <span className={classnames(classes.title)}> - {authors.length === 0 ? 'Submitting author' : 'Author'} - </span> - <div className={classnames(classes.row)}> - <ValidatedTextField - isRequired - label="First name" - name="author.firstName" - /> - <ValidatedTextField label="Middle name" name="author.middleName" /> - <ValidatedTextField isRequired label="Last name" name="author.lastName" /> - </div> - - <div className={classnames(classes.row)}> - <ValidatedTextField - isRequired - label="Email" - name="author.email" - validators={[emailValidator]} - /> - <ValidatedTextField - isRequired - label="Affiliation" - name="author.affiliation" - /> - <MenuItem label="Country" name="author.country" options={countries} /> - </div> - </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, - middleName, - lastName, - email, - affiliation, - country, - isDragging, - dragHandle, - isOver, - countryParser, - removeAuthor, - isSubmitting, - isCorresponding, - setAsCorresponding, - parseAuthorType, -}) => ( - <div - className={classnames({ - [classes.author]: true, - [classes.dashed]: isOver, - })} - > - {!isOver && dragHandle} - <div - className={classnames({ - [classes.container]: true, - [classes.hide]: isOver, - })} - > - <span className={classnames(classes.title)}> - {parseAuthorType(isSubmitting, isCorresponding)} - </span> - <div className={classnames(classes.row)}> - <Label label="First name" value={firstName} /> - <Label label="Middle name" value={middleName} /> - <Label label="Last name" value={lastName} /> - </div> - <div className={classnames(classes.row)}> - <Label label="Email" value={email} /> - <Label label="Affiliation" value={affiliation} /> - <Label label="Country" value={countryParser(country)} /> - </div> - </div> - <div className={classnames(classes['button-container'])}> - {!isSubmitting && ( - <div - className={classnames(classes['delete-button'])} - onClick={removeAuthor(email)} - > - <Icon>trash</Icon> - </div> - )} - {!isCorresponding && ( - <div - className={classnames(classes.corresponding)} - onClick={setAsCorresponding(email)} - > - <Icon>mail</Icon> - </div> - )} - </div> - </div> -) - -const Authors = ({ - author, - authors, - moveAuthor, - addAuthor, - editAuthor, - match, - version, - dropItem, - ...rest -}) => ( - <div> - <Adder - addAuthor={addAuthor} - author={author} - authors={authors} - editAuthor={editAuthor} - match={match} - /> - <SortableList - dragHandle={DragHandle} - dropItem={dropItem} - items={authors} - listItem={Author} - moveItem={moveAuthor} - {...rest} - /> - </div> -) - -export default compose( - withRouter, - getContext({ version: PropTypes.object, project: PropTypes.object }), - connect( - (state, { match: { params: { version } } }) => ({ - authors: getFragmentAuthors(state, version), - }), - { - addAuthor, - setAuthors, - moveAuthors, - updateFragment: actions.updateFragment, - }, - ), - lifecycle({ - componentDidMount() { - const { version, setAuthors } = this.props - setAuthors(version.authors, version.id) - }, - }), - withHandlers({ - dropItem: ({ - updateFragment, - authors, - project, - version, - setAuthors, - }) => () => { - setAuthors(authors, version.id) - }, - countryParser: () => countryCode => - countries.find(c => c.value === countryCode).label, - parseAuthorType: () => (isSubmitting, isCorresponding) => { - if (isSubmitting) return 'Submitting author' - if (isCorresponding) return 'Corresponding author' - return 'Author' - }, - moveAuthor: ({ - authors, - moveAuthors, - project, - version, - updateFragment, - match: { params }, - }) => (dragIndex, hoverIndex) => { - const newAuthors = SortableList.moveItem(authors, dragIndex, hoverIndex) - moveAuthors(newAuthors, params.version) - }, - removeAuthor: ({ - authors, - updateFragment, - project, - version, - setAuthors, - }) => authorEmail => () => { - const newAuthors = authors.filter(a => a.email !== authorEmail) - setAuthors(newAuthors, version.id) - }, - setAsCorresponding: ({ - authors, - updateFragment, - setAuthors, - version, - project, - }) => authorEmail => () => { - const newAuthors = authors.map(a => ({ - ...a, - isCorresponding: a.isSubmitting || a.email === authorEmail, - })) - setAuthors(newAuthors, version.id) - }, - }), -)(Authors) diff --git a/packages/component-wizard/src/components/AuthorList/Author.js b/packages/component-wizard/src/components/AuthorList/Author.js new file mode 100644 index 0000000000000000000000000000000000000000..0a0513d32f7a9bb29fe7fecba19bfc330cfba17e --- /dev/null +++ b/packages/component-wizard/src/components/AuthorList/Author.js @@ -0,0 +1,82 @@ +import React from 'react' +import classnames from 'classnames' +import { Icon } from '@pubsweet/ui' + +import { Label } from './FormItems' +import classes from './AuthorList.local.scss' + +export default ({ + firstName, + middleName, + lastName, + email, + affiliation, + country, + dragHandle, + isOver, + countryParser, + removeAuthor, + isSubmitting, + isCorresponding, + setAsCorresponding, + parseAuthorType, + ...rest +}) => ( + <div + className={classnames({ + [classes.author]: true, + [classes.dashed]: isOver, + })} + > + {!isOver && dragHandle} + <div + className={classnames({ + [classes.container]: true, + [classes.hide]: isOver, + })} + > + <span className={classnames(classes.title)}> + {parseAuthorType(isSubmitting, isCorresponding)} + </span> + <div className={classnames(classes.row)}> + <Label label="First name" value={firstName} /> + <Label label="Middle name" value={middleName} /> + <Label label="Last name" value={lastName} /> + </div> + <div className={classnames(classes.row)}> + <Label label="Email" value={email} /> + <Label label="Affiliation" value={affiliation} /> + <Label label="Country" value={countryParser(country)} /> + </div> + </div> + <div className={classnames(classes['button-container'])}> + {!isSubmitting && ( + <div + className={classnames(classes['delete-button'])} + onClick={removeAuthor(email)} + title="Delete author" + > + <Icon>trash</Icon> + </div> + )} + {!isCorresponding && ( + <div + className={classnames(classes.corresponding)} + onClick={setAsCorresponding(email)} + title="Set as corresponding author" + > + <Icon>mail</Icon> + </div> + )} + {rest.editedAuthor < 0 && ( + <div + className={classnames(classes.corresponding)} + onClick={rest.setAuthorEdit(rest.index)} + title="Edit author" + > + <Icon>edit-2</Icon> + </div> + )} + </div> + </div> +) diff --git a/packages/component-wizard/src/components/AuthorList/AuthorAdder.js b/packages/component-wizard/src/components/AuthorList/AuthorAdder.js new file mode 100644 index 0000000000000000000000000000000000000000..f04209029b7a8c5f878d6abd0af2b157525e0c70 --- /dev/null +++ b/packages/component-wizard/src/components/AuthorList/AuthorAdder.js @@ -0,0 +1,115 @@ +import React from 'react' +import { get } from 'lodash' +import classnames from 'classnames' +import { connect } from 'react-redux' +import { Button } from '@pubsweet/ui' +import { reduxForm } from 'redux-form' +import { compose, withProps } from 'recompose' +import { selectCurrentUser } from 'xpub-selectors' + +import classes from './AuthorList.local.scss' +import { MenuItem, ValidatedTextField } from './FormItems' + +const countries = [ + { label: 'Romania', value: 'ro' }, + { label: 'United Kingdom', value: 'uk' }, + { label: 'Germany', value: 'de' }, + { label: 'France', value: 'fr' }, +] + +const emailRegex = new RegExp(/^\w+([.-]?\w+)*@\w+([.-]?\w+)*(\.\w{2,3})+$/) + +const emailValidator = value => + emailRegex.test(value) ? undefined : 'Invalid email' + +const AuthorAdder = ({ authors, editMode, setEditMode, handleSubmit }) => ( + <div className={classnames(classes.adder)}> + <Button onClick={setEditMode(true)} primary> + {authors.length === 0 ? '+ Add submitting author' : '+ Add author'} + </Button> + {editMode && ( + <div className={classnames(classes['form-body'])}> + <span className={classnames(classes.title)}> + {authors.length === 0 ? 'Submitting author' : 'Author'} + </span> + <div className={classnames(classes.row)}> + <ValidatedTextField + isRequired + label="First name" + name="author.firstName" + /> + <ValidatedTextField label="Middle name" name="author.middleName" /> + <ValidatedTextField + isRequired + label="Last name" + name="author.lastName" + /> + </div> + + <div className={classnames(classes.row)}> + <ValidatedTextField + isRequired + label="Email" + name="author.email" + validators={[emailValidator]} + /> + <ValidatedTextField + isRequired + label="Affiliation" + name="author.affiliation" + /> + <MenuItem label="Country" name="author.country" options={countries} /> + </div> + <div className={classnames(classes['form-buttons'])}> + <Button onClick={setEditMode(false)}>Cancel</Button> + <Button onClick={handleSubmit} primary> + Save + </Button> + </div> + </div> + )} + </div> +) + +export default 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, setEditMode, 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() + setEditMode(false)() + }) + }, + }), +)(AuthorAdder) diff --git a/packages/component-wizard/src/components/AuthorList/AuthorEditor.js b/packages/component-wizard/src/components/AuthorList/AuthorEditor.js new file mode 100644 index 0000000000000000000000000000000000000000..c56421daf1e9e1dedd2502042fee945814eedf93 --- /dev/null +++ b/packages/component-wizard/src/components/AuthorList/AuthorEditor.js @@ -0,0 +1,86 @@ +import React from 'react' +import PropTypes from 'prop-types' +import classnames from 'classnames' +import { connect } from 'react-redux' +import { Button } from '@pubsweet/ui' +import { reduxForm } from 'redux-form' +import { withRouter } from 'react-router-dom' +import { compose, getContext } from 'recompose' + +import { ValidatedTextField, MenuItem } from './FormItems' +import { getFragmentAuthors, setAuthors } from '../../redux/authors' + +import classes from './AuthorList.local.scss' + +const countries = [ + { label: 'Romania', value: 'ro' }, + { label: 'United Kingdom', value: 'uk' }, + { label: 'Germany', value: 'de' }, + { label: 'France', value: 'fr' }, +] + +const emailRegex = new RegExp(/^\w+([.-]?\w+)*@\w+([.-]?\w+)*(\.\w{2,3})+$/) + +const emailValidator = value => + emailRegex.test(value) ? undefined : 'Invalid email' + +const AuthorEdit = ({ setAuthorEdit, handleSubmit }) => ( + <div className={classnames(classes['editor-body'])}> + <div className={classnames(classes.row)}> + <ValidatedTextField isRequired label="First name" name="edit.firstName" /> + <ValidatedTextField label="Middle name" name="edit.middleName" /> + <ValidatedTextField isRequired label="Last name" name="edit.lastName" /> + </div> + + <div className={classnames(classes.row)}> + <ValidatedTextField + isRequired + label="Email" + name="edit.email" + validators={[emailValidator]} + /> + <ValidatedTextField + isRequired + label="Affiliation" + name="edit.affiliation" + /> + <MenuItem label="Country" name="edit.country" options={countries} /> + </div> + + <div className={classnames(classes['form-buttons'])}> + <Button onClick={setAuthorEdit(-1)}>Cancel</Button> + <Button onClick={handleSubmit} primary> + Save + </Button> + </div> + </div> +) + +export default compose( + withRouter, + getContext({ version: PropTypes.object, project: PropTypes.object }), + connect( + (state, { match: { params: { version } } }) => ({ + authors: getFragmentAuthors(state, version), + }), + { + setAuthors, + }, + ), + reduxForm({ + form: 'edit', + onSubmit: ( + values, + dispatch, + { setAuthorEdit, setAuthors, project, version, authors, index, ...rest }, + ) => { + const newAuthors = [ + ...authors.slice(0, index), + values.edit, + ...authors.slice(index + 1), + ] + setAuthors(newAuthors, version.id) + setTimeout(setAuthorEdit(-1), 100) + }, + }), +)(AuthorEdit) diff --git a/packages/component-wizard/src/components/AuthorList/AuthorList.js b/packages/component-wizard/src/components/AuthorList/AuthorList.js new file mode 100644 index 0000000000000000000000000000000000000000..26925c5ca4a16125150e75fb7331ba3a285e972c --- /dev/null +++ b/packages/component-wizard/src/components/AuthorList/AuthorList.js @@ -0,0 +1,150 @@ +import React from 'react' +import PropTypes from 'prop-types' +import { connect } from 'react-redux' +import { withRouter } from 'react-router-dom' +import { + compose, + withHandlers, + getContext, + lifecycle, + withState, +} from 'recompose' + +import { + addAuthor, + getFragmentAuthors, + setAuthors, + moveAuthors, +} from '../../redux/authors' + +import SortableList from '../SortableList' + +import Author from './Author' +import StaticList from './StaticList' +import AuthorAdder from './AuthorAdder' +import AuthorEditor from './AuthorEditor' +import { DragHandle } from './FormItems' + +const countries = [ + { label: 'Romania', value: 'ro' }, + { label: 'United Kingdom', value: 'uk' }, + { label: 'Germany', value: 'de' }, + { label: 'France', value: 'fr' }, +] + +const Authors = ({ + authors, + moveAuthor, + addAuthor, + editAuthor, + match, + version, + dropItem, + editMode, + setEditMode, + editedAuthor, + ...rest +}) => ( + <div> + <AuthorAdder + addAuthor={addAuthor} + authors={authors} + editAuthor={editAuthor} + editMode={editMode} + match={match} + setEditMode={setEditMode} + /> + {editedAuthor > -1 ? ( + <StaticList + authors={authors} + editComponent={AuthorEditor} + editIndex={editedAuthor} + {...rest} + /> + ) : ( + <SortableList + dragHandle={DragHandle} + dropItem={dropItem} + editedAuthor={editedAuthor} + items={authors} + listItem={Author} + moveItem={moveAuthor} + {...rest} + /> + )} + </div> +) + +export default compose( + withRouter, + getContext({ version: PropTypes.object, project: PropTypes.object }), + connect( + (state, { match: { params: { version } } }) => ({ + authors: getFragmentAuthors(state, version), + }), + { + addAuthor, + setAuthors, + moveAuthors, + }, + ), + lifecycle({ + componentDidMount() { + const { version, setAuthors } = this.props + setAuthors(version.authors, version.id) + }, + }), + withState('editMode', 'setEditMode', false), + withState('editedAuthor', 'setEditedAuthor', -1), + withHandlers({ + setAuthorEdit: ({ setEditedAuthor }) => editedAuthor => e => { + e && e.preventDefault && e.preventDefault() + setEditedAuthor(prev => editedAuthor) + }, + setEditMode: ({ setEditMode }) => mode => e => { + e && e.preventDefault() + setEditMode(v => mode) + }, + dropItem: ({ authors, project, version, setAuthors }) => () => { + setAuthors(authors, version.id) + }, + countryParser: () => countryCode => + countries.find(c => c.value === countryCode).label, + parseAuthorType: () => (isSubmitting, isCorresponding) => { + if (isSubmitting) return 'Submitting author' + if (isCorresponding) return 'Corresponding author' + return 'Author' + }, + moveAuthor: ({ + authors, + moveAuthors, + project, + version, + match: { params }, + }) => (dragIndex, hoverIndex) => { + const newAuthors = SortableList.moveItem(authors, dragIndex, hoverIndex) + moveAuthors(newAuthors, params.version) + }, + removeAuthor: ({ + authors, + project, + version, + setAuthors, + }) => authorEmail => () => { + const newAuthors = authors.filter(a => a.email !== authorEmail) + setAuthors(newAuthors, version.id) + }, + setAsCorresponding: ({ + authors, + setAuthors, + version, + project, + }) => authorEmail => () => { + const newAuthors = authors.map(a => ({ + ...a, + isCorresponding: a.isSubmitting || a.email === authorEmail, + })) + setAuthors(newAuthors, version.id) + }, + }), +)(Authors) diff --git a/packages/component-wizard/src/components/AuthorList.local.scss b/packages/component-wizard/src/components/AuthorList/AuthorList.local.scss similarity index 82% rename from packages/component-wizard/src/components/AuthorList.local.scss rename to packages/component-wizard/src/components/AuthorList/AuthorList.local.scss index ea18aada1726cf751e7e5d29f87fe08ceffda286..e9316340c2fbe91ce0d01bc180ddd0f617d364bd 100644 --- a/packages/component-wizard/src/components/AuthorList.local.scss +++ b/packages/component-wizard/src/components/AuthorList/AuthorList.local.scss @@ -48,12 +48,34 @@ } } -.adder { +.editor-body { border: 1px solid #444; + margin: 10px 0; + padding: 10px; + + .form-buttons { + display: flex; + justify-content: space-around; + margin: 15px 0 0 0; + } +} + +.adder { display: flex; flex-direction: column; margin: 10px 0; - padding: 10px; + + .form-body { + border: 1px solid #444; + margin-top: 10px; + padding: 10px; + } + + .form-buttons { + display: flex; + justify-content: space-around; + margin: 15px 0 0 0; + } .button { background-color: #444; @@ -83,15 +105,6 @@ } } -.drag-handle { - align-items: center; - border-right: 1px solid #444; - cursor: move; - display: flex; - flex-direction: column; - justify-content: center; -} - .validated-text { flex: 1; margin-right: 20px; diff --git a/packages/component-wizard/src/components/AuthorList/FormItems.js b/packages/component-wizard/src/components/AuthorList/FormItems.js new file mode 100644 index 0000000000000000000000000000000000000000..a51969f622641759fe00a81fc21479e52a47be81 --- /dev/null +++ b/packages/component-wizard/src/components/AuthorList/FormItems.js @@ -0,0 +1,47 @@ +import React from 'react' +import classnames from 'classnames' +import { required } from 'xpub-validators' +import { TextField, Menu, ValidatedField, Icon } from '@pubsweet/ui' + +import classes from './FormItems.local.scss' + +export const ValidatedTextField = ({ + label, + name, + isRequired, + validators = [], +}) => { + const v = [isRequired && required, ...validators].filter(Boolean) + return ( + <div className={classnames(classes['validated-text'])}> + <span className={classnames(classes.label)}>{label}</span> + <ValidatedField component={TextField} name={name} validate={v} /> + </div> + ) +} + +export const MenuItem = ({ label, name, options }) => ( + <div className={classnames(classes['validated-text'])}> + <span className={classnames(classes.label)}>{label}</span> + <ValidatedField + component={input => <Menu {...input} options={options} />} + name={name} + validate={[required]} + /> + </div> +) + +export 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> +) + +export const DragHandle = () => ( + <div className={classnames(classes['drag-handle'])}> + <Icon>chevron_up</Icon> + <Icon size={16}>menu</Icon> + <Icon>chevron_down</Icon> + </div> +) diff --git a/packages/component-wizard/src/components/AuthorList/FormItems.local.scss b/packages/component-wizard/src/components/AuthorList/FormItems.local.scss new file mode 100644 index 0000000000000000000000000000000000000000..2ffbe88971b4e4a576693d4187701f548244254c --- /dev/null +++ b/packages/component-wizard/src/components/AuthorList/FormItems.local.scss @@ -0,0 +1,31 @@ +.validated-text { + flex: 1; + margin-right: 20px; +} + +.label { + font-size: 14px; + font-weight: 300; + text-transform: uppercase; +} + +.label-container { + display: flex; + flex: 1; + flex-direction: column; + margin: 5px; + + .value { + font-size: 16px; + font-weight: 600; + } +} + +.drag-handle { + align-items: center; + border-right: 1px solid #444; + cursor: move; + display: flex; + flex-direction: column; + justify-content: center; +} diff --git a/packages/component-wizard/src/components/AuthorList/StaticList.js b/packages/component-wizard/src/components/AuthorList/StaticList.js new file mode 100644 index 0000000000000000000000000000000000000000..a0da937295e6a75cb60b8b0a28f4c44e42ff2b8c --- /dev/null +++ b/packages/component-wizard/src/components/AuthorList/StaticList.js @@ -0,0 +1,39 @@ +import React from 'react' + +import Author from './Author' + +export default ({ + authors, + editIndex, + removeAuthor, + countryParser, + editComponent, + setAuthorEdit, + parseAuthorType, +}) => ( + <div> + {authors.map( + (a, index) => + index === editIndex ? ( + React.createElement(editComponent, { + key: 'author-editor', + index, + initialValues: { + edit: a, + }, + setAuthorEdit, + countryParser, + parseAuthorType, + }) + ) : ( + <Author + key={a.firstName} + {...a} + countryParser={countryParser} + parseAuthorType={parseAuthorType} + removeAuthor={removeAuthor} + /> + ), + )} + </div> +) diff --git a/packages/component-wizard/src/components/AuthorList/index.js b/packages/component-wizard/src/components/AuthorList/index.js new file mode 100644 index 0000000000000000000000000000000000000000..473f04dcd0b9fba6f38dd46e866126960656c2f2 --- /dev/null +++ b/packages/component-wizard/src/components/AuthorList/index.js @@ -0,0 +1 @@ +export { default as AuthorList } from './AuthorList' diff --git a/packages/component-wizard/src/components/SortableList.js b/packages/component-wizard/src/components/SortableList.js index c566f4c63de5337bf218b660660c311efe308b92..b52ad3f7a4b8d487771521c18ba68e4a9c000a70 100644 --- a/packages/component-wizard/src/components/SortableList.js +++ b/packages/component-wizard/src/components/SortableList.js @@ -47,6 +47,7 @@ const Item = ({ connectDropTarget, listItem, dragHandle, + isEditing, ...rest }) => dragHandle @@ -82,12 +83,20 @@ const DecoratedItem = compose( })), )(Item) -const SortableList = ({ items, moveItem, listItem, dragHandle, ...rest }) => ( +const SortableList = ({ + items, + moveItem, + listItem, + dragHandle, + editItem, + ...rest +}) => ( <div> {items.map((item, i) => ( <DecoratedItem dragHandle={dragHandle} index={i} + isEditing={rest.editedAuthor !== -1} key={item.name || Math.random()} listItem={listItem} moveItem={moveItem} diff --git a/packages/component-wizard/src/components/WizardStep.js b/packages/component-wizard/src/components/WizardStep.js index dde7bcf9f1d1e829b39c09c06fdfe6508cedf943..4a3c7b8cb515efde8f8520c5c446d1588597de16 100644 --- a/packages/component-wizard/src/components/WizardStep.js +++ b/packages/component-wizard/src/components/WizardStep.js @@ -4,6 +4,7 @@ import classnames from 'classnames' import { ValidatedField, Button } from '@pubsweet/ui' import classes from './WizardStep.local.scss' +import AuthorList from './AuthorList/AuthorList' export default ({ children: stepChildren, @@ -60,6 +61,7 @@ export default ({ ) }, )} + <AuthorList /> <div className={classnames(classes.buttons)}> <Button onClick={isFirst ? () => history.push('/') : prevStep}> {isFirst diff --git a/packages/component-wizard/src/components/index.js b/packages/component-wizard/src/components/index.js index 710ecfaa0eddf11223519e338a929598aeffe755..6fc7c641ca9fa351c3c8c0e8147281cfcfa49b0a 100644 --- a/packages/component-wizard/src/components/index.js +++ b/packages/component-wizard/src/components/index.js @@ -5,5 +5,3 @@ export { default as WizardPage } from './WizardPage' export { default as WizardStep } from './WizardStep' export { default as SortableList } from './SortableList' export { default as WizardFormStep } from './WizardFormStep' - -export { default as AuthorList } from './AuthorList' diff --git a/packages/component-wizard/src/redux/authors.js b/packages/component-wizard/src/redux/authors.js index 18440cfd06b64e78b1a3987f118a3352b17abbe5..0ee3777b5b8e5f0936c38b0145839df0cec39778 100644 --- a/packages/component-wizard/src/redux/authors.js +++ b/packages/component-wizard/src/redux/authors.js @@ -14,8 +14,8 @@ const _setAuthors = (authors, fragmentId) => ({ // actions export const setAuthors = (authors, fragmentId) => dispatch => { - dispatch(_setAuthors(authors, fragmentId)) dispatch(change('wizard', 'authors', authors)) + dispatch(_setAuthors(authors, fragmentId)) } export const moveAuthors = (authors, fragmentId) => dispatch => { diff --git a/packages/xpub-faraday/app/config/journal/submit-wizard.js b/packages/xpub-faraday/app/config/journal/submit-wizard.js index 8dc2c491eea9cec3fccb21bd46ce730e3baeafe5..13d09c207eeee61a7daba330f5dbe5b140b1e323 100644 --- a/packages/xpub-faraday/app/config/journal/submit-wizard.js +++ b/packages/xpub-faraday/app/config/journal/submit-wizard.js @@ -9,7 +9,7 @@ import { } from '@pubsweet/ui' import uploadFileFn from 'xpub-upload' import { required, minChars, minSize } from 'xpub-validators' -import { AuthorList } from 'pubsweet-component-wizard/src/components' +import { AuthorList } from 'pubsweet-component-wizard/src/components/AuthorList' import { declarations } from './' import issueTypes from './issues-types'